在说 spring 的 ioc 之前我想先说说 spring 实现 ioc 机制的重要技术——反射。在 jdk 中对 java.lang.reflect 包的描述:提供类和接口,以获得关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对其底层对等项进行操作。这段话听起来还挺复杂,我理解该包提供了用于获取类和对象的反射信息的一系列的类和接口。那么所谓的反射信息包含哪些呢?主要就是类的属性、方法、和构造方法。并可以操作对等底层字节码文件。下面就通过代码来看看反射暴力到底提供了什么好用的方法。
首先说说包中常用几个的接口和类:
Class:Class 类的实例表示正在运行的 Java 应用程序中的类和接口。通过 java 源代码不难发现 Class 对象只由 jvm 创建。Class 类中提供了许多反射常用的静态方法:
- 1@CallerSensitive 2 public static Class forName(String className) 3 throws ClassNotFoundException {
- 4
- return forName0(className, true, 5 ClassLoader.getClassLoader(Reflection.getCallerClass()));
- 6
- }
- 1@CallerSensitive 2 public static Class forName(String name, boolean initialize, 3 ClassLoader loader) 4 throws ClassNotFoundException 5 {
- 6
- if (loader == null) {
- 7 SecurityManager sm = System.getSecurityManager();
- 8
- if (sm != null) {
- 9 ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
- 10
- if (ccl != null) {
- 11 sm.checkPermission(12 SecurityConstants.GET_CLASSLOADER_PERMISSION);
- 13
- }
- 14
- }
- 15
- }
- 16
- return forName0(name, initialize, loader);
- 17
- }
上述代码提供了两种类的加载方式,使用 jdbc 操作过数据库的同学对这两种方式想必不会陌生。
- 1@CallerSensitive 2 public ClassLoader getClassLoader() {
- 3 ClassLoader cl = getClassLoader0();
- 4
- if (cl == null) 5
- return null;
- 6 SecurityManager sm = System.getSecurityManager();
- 7
- if (sm != null) {
- 8 ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
- 9
- }
- 10
- return cl;
- 11
- }
以上是用于获取当前类的加载器的方法。
- @CallerSensitive public T newInstance() throws InstantiationException,
- IllegalAccessException {
- if (System.getSecurityManager() != null) {
- checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
- }
- // NOTE: the following code may not be strictly correct under
- // the current Java memory model.
- // Constructor lookup
- if (cachedConstructor == null) {
- if (this == Class.class) {
- throw new IllegalAccessException("Can not call newInstance() on the Class for java.lang.Class");
- }
- try {
- Class[] empty = {};
- final Constructor c = getConstructor0(empty, Member.DECLARED);
- // Disable accessibility checks on the constructor
- // since we have to do the security check here anyway
- // (the stack depth is wrong for the Constructor's
- // security check to work)
- java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
- public Void run() {
- c.setAccessible(true);
- return null;
- }
- });
- cachedConstructor = c;
- } catch(NoSuchMethodException e) {
- throw new InstantiationException(getName());
- }
- }
- Constructor tmpConstructor = cachedConstructor;
- // Security check (same as in java.lang.reflect.Constructor)
- int modifiers = tmpConstructor.getModifiers();
- if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
- Class caller = Reflection.getCallerClass();
- if (newInstanceCallerCache != caller) {
- Reflection.ensureMemberAccess(caller, this, null, modifiers);
- newInstanceCallerCache = caller;
- }
- }
- // Run constructor
- try {
- return tmpConstructor.newInstance((Object[]) null);
- } catch(InvocationTargetException e) {
- Unsafe.getUnsafe().throwException(e.getTargetException());
- // Not reached
- return null;
- }
- }
以上是实例化一个类的方法。
- public String getName() {
- String name = this.name;
- if (name == null) this.name = name = getName0();
- return name;
- }
以上这段代码是获取类的名称的方法。注意该方法返回的是全包名 + 类名。
- 1 public String getSimpleName() {
- 2
- if (isArray()) 3
- return getComponentType().getSimpleName() + "[]";
- 4 5 String simpleName = getSimpleBinaryName();
- 6
- if (simpleName == null) { // top level class
- 7 simpleName = getName();
- 8
- return simpleName.substring(simpleName.lastIndexOf(".") + 1); // strip the package name
- 9
- }
- 10 // According to JLS3 "Binary Compatibility" (13.1) the binary
- 11 // name of non-package classes (not top level) is the binary
- 12 // name of the immediately enclosing class followed by a '$' followed by:
- 13 // (for nested and inner classes): the simple name.
- 14 // (for local classes): 1 or more digits followed by the simple name.
- 15 // (for anonymous classes): 1 or more digits.
- 16 17 // Since getSimpleBinaryName() will strip the binary name of
- 18 // the immediatly enclosing class, we are now looking at a
- 19 // string that matches the regular expression "\$[0-9]*"
- 20 // followed by a simple name (considering the simple of an
- 21 // anonymous class to be the empty string).
- 22 23 // Remove leading "\$[0-9]*" from the name
- 24 int length = simpleName.length();
- 25
- if (length < 1 || simpleName.charAt(0) != '$') 26
- throw new InternalError("Malformed class name");
- 27 int index = 1;
- 28
- while (index < length && isAsciiDigit(simpleName.charAt(index))) 29 index++;
- 30 // Eventually, this is the empty string iff this is an anonymous class
- 31
- return simpleName.substring(index);
- 32
- }
以上代码是用于获取累的简单名称的方法,不包含包名。
下面是一个简单示例:
- 1 package com.baobaotao;
- 2 3 public class Test {
- 4 public static void main(String[] args) throws ClassNotFoundException {
- 5 Class clz = Class.forName("com.baobaotao.Person");
- 6 System.out.println(clz.getName());
- 7
- }
- 8
- }
- 9 10 class Person {
- 11 private String name;
- 12 public Person() {}
- 13 public Person(String name) {
- 14 this.name = name;
- 15
- }
- 16 public String getName() {
- 17
- return this.name;
- 18
- }
- 19
- }
输出结果:
- com.baobaotao.Person
- 注意:红色部分不可写成"Person"必须是全包名 + 类名。否则报"java.lang.ClassNotFoundException".
- 1@CallerSensitive 2 public Constructor getConstructor(Class...parameterTypes) 3 throws NoSuchMethodException,
- SecurityException {
- 4 // be very careful not to change the stack depth of this
- 5 // checkMemberAccess call for security reasons
- 6 // see java.lang.SecurityManager.checkMemberAccess
- 7 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
- 8
- return getConstructor0(parameterTypes, Member.PUBLIC);
- 9
- }
这个方法适用于获取类中拥有指定参数类型的构造方法。
- 1@CallerSensitive 2 public Constructor[] getConstructors() throws SecurityException {
- 3 // be very careful not to change the stack depth of this
- 4 // checkMemberAccess call for security reasons
- 5 // see java.lang.SecurityManager.checkMemberAccess
- 6 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
- 7
- return copyConstructors(privateGetDeclaredConstructors(true));
- 8
- }
若要获取类中所有的构造函数则需要使用上面方法。
- 1@CallerSensitive 2 public Method[] getMethods() throws SecurityException {
- 3 // be very careful not to change the stack depth of this
- 4 // checkMemberAccess call for security reasons
- 5 // see java.lang.SecurityManager.checkMemberAccess
- 6 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
- 7
- return copyMethods(privateGetPublicMethods());
- 8
- }
- 1@CallerSensitive 2 public Method getMethod(String name, Class...parameterTypes) 3 throws NoSuchMethodException,
- SecurityException {
- 4 // be very careful not to change the stack depth of this
- 5 // checkMemberAccess call for security reasons
- 6 // see java.lang.SecurityManager.checkMemberAccess
- 7 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
- 8 Method method = getMethod0(name, parameterTypes);
- 9
- if (method == null) {
- 10
- throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
- 11
- }
- 12
- return method;
- 13
- }
上述两个方法主要用于获取类中所有方法和指定名称的方法。
- 1@CallerSensitive 2 public Field[] getFields() throws SecurityException {
- 3 // be very careful not to change the stack depth of this
- 4 // checkMemberAccess call for security reasons
- 5 // see java.lang.SecurityManager.checkMemberAccess
- 6 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
- 7
- return copyFields(privateGetPublicFields(null));
- 8
- }
- 1@CallerSensitive 2 public Field getField(String name) 3 throws NoSuchFieldException,
- SecurityException {
- 4 // be very careful not to change the stack depth of this
- 5 // checkMemberAccess call for security reasons
- 6 // see java.lang.SecurityManager.checkMemberAccess
- 7 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
- 8 Field field = getField0(name);
- 9
- if (field == null) {
- 10
- throw new NoSuchFieldException(name);
- 11
- }
- 12
- return field;
- 13
- }
上述是获取类中所有属性和获取类中指定属性的方法。
另外,Class 还提供了另外一组获取类属性、方法、构造的方法
- 1@CallerSensitive 2 public Field[] getDeclaredFields() throws SecurityException {
- 3 // be very careful not to change the stack depth of this
- 4 // checkMemberAccess call for security reasons
- 5 // see java.lang.SecurityManager.checkMemberAccess
- 6 checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
- 7
- return copyFields(privateGetDeclaredFields(false));
- 8
- }
- 9 10@CallerSensitive 11 public Field getDeclaredField(String name) 12 throws NoSuchFieldException,
- SecurityException {
- 13 // be very careful not to change the stack depth of this
- 14 // checkMemberAccess call for security reasons
- 15 // see java.lang.SecurityManager.checkMemberAccess
- 16 checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
- 17 Field field = searchFields(privateGetDeclaredFields(false), name);
- 18
- if (field == null) {
- 19
- throw new NoSuchFieldException(name);
- 20
- }
- 21
- return field;
- 22
- }
- 23 24@CallerSensitive 25 public Method getDeclaredMethod(String name, Class...parameterTypes) 26 throws NoSuchMethodException,
- SecurityException {
- 27 // be very careful not to change the stack depth of this
- 28 // checkMemberAccess call for security reasons
- 29 // see java.lang.SecurityManager.checkMemberAccess
- 30 checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
- 31 Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
- 32
- if (method == null) {
- 33
- throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
- 34
- }
- 35
- return method;
- 36
- }
- 37 38@CallerSensitive 39 public Method[] getDeclaredMethods() throws SecurityException {
- 40 // be very careful not to change the stack depth of this
- 41 // checkMemberAccess call for security reasons
- 42 // see java.lang.SecurityManager.checkMemberAccess
- 43 checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
- 44
- return copyMethods(privateGetDeclaredMethods(false));
- 45
- }
那么,两种方式有什么区别呢?带有 Declared 的方法获取的是该类中所有的方法、属性或者构造。而不带 Declared 的只是获取访问修饰符为 public(公共的)属性、方法和构造。
Class 类中还提供了两种常用的获取资源的方法:
- 1 public java.net.URL getResource(String name) {
- 2 name = resolveName(name);
- 3 ClassLoader cl = getClassLoader0();
- 4
- if (cl == null) {
- 5 // A system class.
- 6
- return ClassLoader.getSystemResource(name);
- 7
- }
- 8
- return cl.getResource(name);
- 9
- }
- 10 11 12 public InputStream getResourceAsStream(String name) {
- 13 name = resolveName(name);
- 14 ClassLoader cl = getClassLoader0();
- 15
- if (cl == null) {
- 16 // A system class.
- 17
- return ClassLoader.getSystemResourceAsStream(name);
- 18
- }
- 19
- return cl.getResourceAsStream(name);
- 20
- }
两种方式分别返回 java.net.URL 对象和流对象。
Class 类中海油许多方法,这里只是列出了一些个人认为比较常用的方法,其实所有的方法在 API 中都可以清晰的查到,这里我之所以附上源码一个个列出来主要是可以让自己看到其内部的实现,可以理解的更加深刻。以后还会写博专门陈述一下以上理论的具体使用。
来源: http://www.cnblogs.com/kemir1105/p/6002229.html