反射定義
在運行狀態中,對任意一個類,都能知道這個類中所有的屬性和方法;對於任意一個對象,都能調用它的任意一個方法和屬性。
反射的使用過程中要基於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加載的類不進行解析操作,不進行解析操作就意味着初始化也不會進行,那麼其類的靜態參數就不會初始化,靜態代碼塊也不會被執行。