Java反射机制( java.lang.reflect )
反射机制是在 运行状态 中:
对于任意一个类,都能够知道 这个类的所有属性及方法 ;
对于任意一个对象, 都能够 调用它的任意一个方法和属性 ;
这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制。
获取 Class 对象方法:
Class.forName(), classLoader.loadClass(), class.getClass()
Class 类方法:
getClassLoader(): ClassLoader
forName(String className): Class<?>
getDeclaredMethod(String name, Class<?>... parameterTypes): Method
getDeclaredField(String name): Field
getConstructor(Class<?>... parameterTypes): Constructor<T>
Class.forName() 和 classLoader.loadClass() 的区别:
-
Class.forName() 在类加载的时候会执行静态代码块, 而 classLoader.loadClass() 只有在调用 newInstance() 时才会执行静态代码块
-
初始化不同:
Class.forName() 会对类初始化,而loadClass()只会装载或链接。可见的效果就是类中静态初始化段及字节码中对所有静态成员的初始工作的执行(这个过程在类的所有父类中递归地调用)。这点就与 classLoader.loadClass() 不同。 classLoader.loadClass() 加载的类对象是在第一次被调用时才进行初始化的。你可以利用上述的差异.比如,要加载一个静态初始化开销很大的类,你就可以选择提前加载该类(以确保它在classpath下),但不进行初始化,直到第一次使用该类的域或方法时才进行初始化 -
类加载器不同:
Class.forName(String) 方法(只有一个参数),使用调用者的类加载器来加载,也就是用加载了调用 forName() 方法的代码的那个类加载器。当然,它也有个重载的方法,可以指定加载器。相应的, classLoader.loadClass() 方法是一个实例方法(非静态方法),调用时需要自己指定类加载器,那么这个类加载器就可能是也可能不是加载调用代码的类加载器(调用代码类加载器通过getClassLoader())获得
Class.forName(String) :
/**
* Returns the {@code Class} object associated with the class or
* interface with the given string name. Invoking this method is
* equivalent to:
*
* <blockquote>
* {@code Class.forName(className, true, currentLoader)}
* </blockquote>
*
* where {@code currentLoader} denotes the defining class loader of
* the current class.
*
* <p> For example, the following code fragment returns the
* runtime {@code Class} descriptor for the class named
* {@code java.lang.Thread}:
*
* <blockquote>
* {@code Class t = Class.forName("java.lang.Thread")}
* </blockquote>
* <p>
* A call to {@code forName("X")} causes the class named //会被初始化
* {@code X} to be initialized.
*
* @param className the fully qualified name of the desired class.
* @return the {@code Class} object for the class with the
* specified name.
* @exception LinkageError if the linkage fails
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails
* @exception ClassNotFoundException if the class cannot be located
*/
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
classLoader.loadClass() :
/**
* Loads the class with the specified <a href="#binary-name">binary name</a>.
* This method searches for classes in the same manner as the {@link
* #loadClass(String, boolean)} method. It is invoked by the Java virtual
* machine to resolve class references. Invoking this method is equivalent
* to invoking {@link #loadClass(String, boolean) loadClass(name,
* false)}.
*
* @param name
* The <a href="#binary-name">binary name</a> of the class
*
* @return The resulting {@code Class} object
*
* @throws ClassNotFoundException
* If the class was not found
*/
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
注意:源码中的 binary name 指的是类的原名(如: Object 的 binary name 是 java.lang.Object )
测试用例:
public class Line {
static {
System.out.println("Line - 静态代码块执行了");
}
}
public class Point {
static {
System.out.println("Point - 静态代码块执行了");
}
}
public class ReflectTest {
public static void main(String[] args) {
String wholeNameLine = "SourceDoc.Line";
String wholeNamePoint = "SourceDoc.Point";
System.out.println("下面是测试ClassLoader.loadClass()的效果");
testClassloader(wholeNameLine, wholeNamePoint);
System.out.println("----------------------------------");
System.out.println("下面是测试Class.forName()的效果");
testForName(wholeNameLine, wholeNamePoint);
}
private static void testClassloader(String wholeNameLine, String wholeNamePoint) {
Class<?> line;
Class<?> point;
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try {
line = classLoader.loadClass(wholeNameLine);
point = classLoader.loadClass(wholeNamePoint);
System.out.println("line " + line.getName());
System.out.println("point " + point.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
private static void testForName(String wholeNameLine, String wholeNamePoint) {
try {
Class<?> line = Class.forName(wholeNameLine);
Class<?> point = Class.forName(wholeNamePoint);
System.out.println("line " + line.getName());
System.out.println("point " + point.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果如下:
下面是测试Classloader的效果
line SourceDoc.Line
point SourceDoc.Point
----------------------------------
下面是测试Class.forName()的效果
Line - 静态代码块执行了
Point - 静态代码块执行了
line SourceDoc.Line
point SourceDoc.Point