自己寫的java.lang.String能否被加載

如題,作者之前對於自己寫的java.lang.String類能否被加載,一直感到非常困惑,今天寫代碼證實了一下。上乾貨。
自己寫類加載器:

public class MyClassLoader extends ClassLoader{
	public Class findClass(String name){
		byte[] b = null;
		try {
			b = getByte(name);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return defineClass(null, b, 0, b.length);
	}
	private byte[] getByte(String name) throws IOException{
		FileInputStream in = new FileInputStream(name);
		byte[] b = new byte[1024];
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int len = 0;
		while((len = in.read(b)) != -1){
			out.write(b, 0, len);
		}
		out.close();
		b = out.toByteArray();
		return b;
	}
	}

測試類(path1,path2是我存放編譯後的class文件的路徑):

	public class MyClassLoaderTest {
	public static void main(String [] args) throws Exception{
		MyClassLoader myloader = new MyClassLoader();
		String path1 = "F:/Software/java/jdk/lib/String.class";
		String path2 = "E:/JavaTest/String.class";
		Class c = myloader.findClass(path1);
		//Class c = myloader.findClass(path2);
		Object obj = c.newInstance();
		System.out.println(obj.getClass().getName());
		Method m = c.getMethod("say", null);
		m.invoke(obj, null);
	}
	}

下面展示了幾個自己寫的package不同其他內容相同的String類,編譯後放在上述path1,path2下各一份。

package java.lang;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

執行main方法,拋異常了:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang

若String寫成下面這樣(注意,只是package有變化):

package java;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

拋異常如下:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java

把String的package改成下面這樣

package java.haha;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

還是拋異常:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.haha

注意,以上三個String類只是package不同。而從以上所拋異常來看,jvm不允許我們自己用"java"開頭的package。再看以下兩種package寫法:

(不寫package)

public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

(package不以“java”開頭)

package lang.java;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

兩種寫法的執行結果,輸出如下:

	String
	I'm String class

這時候我自己寫的String類,被我自己寫的類加載器加載成功,並且通過反射機制,執行了其中的say()方法。

那麼來一個小結吧。

  • 自己寫的類的package名稱不可以"java"開頭,否則不會被類加載器加載。
    (所以自己寫的java.lang.String,肯定也不會被加載成功了,即使是自己寫的類加載器)
  • package不以"java"開頭的類,可被成功加載。
    然而,此時的String類,類名叫做"String",還是叫做"Ergou",還是叫做"ZhangSan"都是無所謂的,只是非常普通的一個名字而已,因爲所屬的package不同,該String類和java.lang.String並不衝突。

結題:

至此,自己寫的java.lang.String能否被加載已經有了答案。
不能!
能被加載的,是lang.java.String,是haha.String,是zhangsan.String…是所有package不以"java"開頭的String。此時,他早已不是那個他…

以上,乃個人愚見,謹與諸君分享,若有不對之處,請不吝賜教。

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