如題,作者之前對於自己寫的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。此時,他早已不是那個他…
以上,乃個人愚見,謹與諸君分享,若有不對之處,請不吝賜教。