兩個類來源於同一個Class文件,被同一個虛擬機加載,只要他們的類加載器不同,那麼這兩個類就必定不相等,也就是說判斷兩個類是否相等,取決於兩個條件:1、類本身,2、加載該類的類加載器
下面詳細解析:
類加載器雖然只用於實現類的加載動作,但它在java程序中起到的作用卻遠遠不限於類加載階段。對於任意一個類,都需要由加載它的類加載器和這個類本身一同確立其在Java虛擬機中的唯一性,每一個類加載器,都擁有一個獨立的類名稱空間。這句話可以表達的更通俗一些:比較兩個類是否“相等”,只有在這兩個類是由同一個類加載器加載的前提下才有意義,否則,即使這兩個類來源於同一個Class文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那麼這兩個類就必定不相等。
這裏所指的“相等”,包括代表類的Class對象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回結果,也包括使用instanceof關鍵字做對象所屬關係判定等情況。如果沒有注意到類加載器的影響,在某些情況下可能會產生具有迷惑性的結果,如下代碼清單演示了不同的類加載器對instanceof關鍵字運算的結果的影響。
package com.school.eution.accommodation;
import java.io.IOException;
import java.io.InputStream;
/**
* 類加載器與instanceof關鍵字演示
*
* @author pocher
*/
public class ClassLoaderTest {
public static void main(String[] args) {
ClassLoader myLoad = new ClassLoader() {
@Override
public Class<?> loadClass(String name)throws ClassNotFoundException {
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is = getClass().getResourceAsStream(fileName);
if (null == is) {
return super.loadClass(name);
}
try {
byte[] b= new byte[is.available()];
is.read(b);
return defineClass(name,b,0,b.length);
} catch (IOException e) {
throw new ClassNotFoundException();
}
}
};
try {
Object obj = myLoad.loadClass("com.school.eution.accommodation.ClassLoaderTest").newInstance();
System.out.println(obj.getClass());
// 這個obj使用的是自定義的classLoad 與 虛擬機自帶的不是一個類加載器,所以返回false
System.out.println(obj instanceof ClassLoaderTest);
System.out.println();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
e.printStackTrace();
}
}
}
運行結果:
Connected to the target VM, address: '127.0.0.1:63977', transport: 'socket'
class com.school.eution.accommodation.ClassLoaderTest
false
以上代碼構造了一個簡單的類加載器,儘管簡單,但是對於這個演示來說還是夠用了。它可以加載與自己在同一路徑下的Class文件。我們使用這個類加載器去加載了一個名爲“com.school.eution.accommodation.ClassLoaderTest”的類,並實例化了這個類的對象。兩行輸出結果中,從第一句可以看出,這個對象確實是類“com.school.eution.accommodation.ClassLoaderTest”實例化出來的對象,但從第二句可以發現,這個對象與類“com.school.eution.accommodation.ClassLoaderTest”做所屬類型檢查的時候卻返回了false,這是因爲虛擬機中存在了兩個ClassLoaderTest類,一個是由系統應用程序類加載器加載的,另一個是有我們自定義的類加載器加載的,雖然都來自同一個Class文件,但依然是兩個獨立的類,作對象所屬類型檢查時結果自然爲false。
參考:《深入理解JVM虛擬機》