類與類加載器【深入分析版】

兩個類來源於同一個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虛擬機》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章