running programmer——spring02(反射)
在说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<T> 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<Void>() { public Void run() { c.setAccessible(true); return null; } }); cachedConstructor = c; } catch (NoSuchMethodException e) { throw new InstantiationException(getName()); } } Constructor<T> 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<T> 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中都可以清晰的查到,这里我之所以附上源码一个个列出来主要是可以让自己看到其内部的实现,可以理解的更加深刻。以后还会写博专门陈述一下以上理论的具体使用。

浙公网安备 33010602011771号