問題: 如果自己定義一個java.lang.String並運行會出現什么情況?
我們看看下面的代碼:
1 package java.lang; 2 public class String{ 3 public static void main(String[] args ){ 4 } 5 }
大家發現什么不同了嗎?對了,我們寫了一個與JDK中String一模一樣的類,連包java.lang都一樣,唯一不同的是我們自定義的String類有一個main函數。我們來運行一下:
java.lang.NoSuchMethodError: main
Exception in thread "main"
這是為什么? 我們的String類不是明明有main方法嗎?
其實聯系到jvm類加載的雙親委托模型,我們就能解釋這個問題了。
運行這段代碼,AppClassLoader會嘗試加載java.lang.String這個類,但是根據雙親委托模型AppClassLoader會將加載java.lang.String的請求委托給ExtClassLoader,而 ExtClassLoader又會委托給最后的啟動類加載器BootstrapLoader。
啟動類加載器BootstrapLoader只能加載JAVA_HOME\jre\lib中的class類(即J2SE API),問題是標准API中確實有一個java.lang.String(注意,這個類和我們自定義的類是完全兩個類)。BootstrapLoader以為找到了這個類,毫不猶豫的加載了j2se api中的java.lang.String。
最后出現上面的加載錯誤(注意不是異常,是錯誤,JVM退出),因為API中的String類是沒有main方法的。
結論:我們當然可以自定義一個和API完全一樣的類,但是由於雙親委托模型,使得我們不可能加載上我們自定義的這樣一個類。所以J2SE規范中希望我們自定義的包有自己唯一的特色(網絡域名)。還有一點,這種加載器原理使得JVM更加安全的運行程序,因為黑客很難隨意的替代掉API中的代碼了。
參照:http://hxraid.iteye.com/blog/747625