反射定义
在运行状态中,对任意一个类,都能知道这个类中所有的属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。
反射的使用过程中要基于Class对象,那通过Class.forName()或者ClassLoader.loadClass()获取Class有什么区别呢?
查看Class.forName()源码
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
//调用三个参数的forName方法
return forName(className, true, VMStack.getCallingClassLoader());
}
...
...
/*
* @param name fully qualified name of the desired class
* @param initialize if {@code true} the class will be initialized.
* See Section 12.4 of <em>The Java Language Specification</em>.
* @param loader class loader from which the class must be loaded
*/
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
loader = BootClassLoader.getInstance();
}
Class<?> result;
try {
result = classForName(name, initialize, loader);
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof LinkageError) {
throw (LinkageError) cause;
}
throw e;
}
return result;
}
/** Called after security checks have been made. */
@FastNative
static native Class<?> classForName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException;
代码中调用Class.forName(String className)实际上会调到 forName(String name, boolean initialize,ClassLoader loader)方法
看方法注释,我们可以了解到第二个参数的含义是class是否将被初始化;
第三个参数传入的是VMStack.getCallingClassLoader(),这里根据方法注释(class loader from which the class must be loaded)可以知道VMStack.getCallingClassLoader()返回的是Class.forName(String className) 加载className类用的ClassLoader,由我的另一篇文章(《Android中ClassLoader双亲委托机制》)中介绍的那样,我们自己写的Android应用的代码都是PathClassLoader加载。所以说这里的第三个参数是PathClassLoader
重点是第二个参数,传入了true,也就是说类会被初始化
我们知道类的加载流程是:加载-链接-初始化-使用-卸载
类一旦被初始化了,类的静态变量就回被初始化,静态代码块就会被执行
写个例子测一下
public class TestBean {
public static String param1 ="testBean";
static {
Log.i("himi",param1+",静态代码块被加载");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Class<?> aClass = Class.forName("com.himi.TestBean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出:
I/himi: testBean,静态代码块被加载
查看ClassLoader.loadClass()源码
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
...
...
/**
* @param resolve
* If <tt>true</tt> then resolve the class
*/
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
loadClass(String name)方法调用了loadClass(String name, boolean resolve),resolve为false,即为通过ClassLoader.loadClass加载的类不进行解析操作,不进行解析操作就意味着初始化也不会进行,那么其类的静态参数就不会初始化,静态代码块也不会被执行。
再来看看代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
//Class<?> aClass = Class.forName("com.himi.TestBean");
Class<?> aClass = getClassLoader().loadClass("com.himi.TestBean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
控制台不会打印“静态代码块被加载”。
总结
Class.forName()加载的类会被初始化,类中的静态成员变量会被初始化,静态代码块会被执行
通过ClassLoader.loadClass加载的类不进行解析操作,不进行解析操作就意味着初始化也不会进行,那么其类的静态参数就不会初始化,静态代码块也不会被执行。