2013-01-15 152 views
10

我試圖在我的eclipse工作區的java.lang包中創建一個自定義的類字符串。 起初我懷疑,在同一個包一個相同的類不能被創建,但我絕對驚訝我能在同一個包來創建一個類(字符串),即java.lang中自定義字符串類的創建

現在我很困惑
1)爲什麼是否有可能,並且
2)如果允許,可能是什麼原因。
3)如果在Java中允許這種類型的Java類創建,會有什麼用處。

+0

如果記錯,所述'java.lang'包[密封(http://docs.oracle.com/javase/6/docs/technotes/指南/擴展/ spec.html#密封),所以你不能添加成員。如果在運行時jar中替換String類型而不在運行時jar中取得成功,我會感到驚訝,因爲該類型對於JVM的操作有多基礎。 – McDowell

回答

9

您可以在java.lang包中創建一個新的類。如果禁止Oracle開發人員如何能夠開發Java?我確定他們使用和我們一樣的javac。

但是您將無法加載它,因爲java.lang。類加載器(任何類加載器擴展)不允許這樣做,每一個被加載的類經過該檢查

... 
     if ((name != null) && name.startsWith("java.")) { 
      throw new SecurityException 
       ("Prohibited package name: " + name.substring(0, name.lastIndexOf('.'))); 
     } 
... 

所以你會在什麼落得像

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang 
    at java.lang.ClassLoader.preDefineClass(ClassLoader.java:649) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:785) 
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) 
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356) 
    at Test1.main(Test1.java:11) 

至於那黑影現有的類象類你的java.lang.String它們不能被加載,因爲System ClassLoader(默認的)使用「父第一」策略,所以java.lang類將通過引導類加載器從rt.jar加載。所以你需要用你的版本替換rt.jar中的String.class。或覆蓋它使用-Xbootclasspath/p: java選項,其中preprends路徑引導類加載器搜索路徑。所以,你可以

1)copypaste真正String.java內容到您的String.java

2)改變的方法,例如

public static String valueOf(double d) { 
    return "Hi"; 
} 

和編譯String.java

3)創建一個測試類

public class Test1 { 

    public static void main(String[] args) throws Exception { 
     System.out.println(String.valueOf(1.0d)); 
    } 
} 

4)運行它爲

java -Xbootclasspath/p:path_to_your_classes Test1 

,你會看到

Hi 
+1

此答案如何回答OP指出的3個問題? – SpaceTrucker

2

是的,您可以創建名稱爲java.lang的包以及名爲的字符串字符串

但是你不能運行你的String類。

1)爲什麼有可能:編譯器會成功編譯你的類。

2)如果允許,可能是什麼原因:您的包和類有一個有效的名稱,所以編譯器不會發出抱怨。

3)如果在Java中允許創建Java類的這種類型,那麼會有什麼用處:但是這個String類沒有太多用處。 Bootstrap類加載器將從sun的java.lang包加載類。所以你的自定義字符串類將不會被加載,因此它在運行時會失敗。

引導類加載器是JVM實現的一部分,它加載了Java API類(包括java.lang.String)。同樣對於每個被加載的類,JVM都會跟蹤哪個類加載器是引導程序還是用戶定義的 - 加載類。因此,加載自定義String類的任何嘗試都將失敗,因爲String類已被加載。

+0

你應該解釋他爲什麼不能跑步。 – SpaceTrucker

+0

我想我已經解釋了... –

+0

感謝rai.sKumar,如果我有兩個選擇答案的選擇,我會明確選擇這個作爲第二個最佳答案。因爲它很清楚,準確而且重要。但Evgeniy Dorofeev所選擇的答案是這樣的(即使是代碼),即使是外行人也能理解和模擬問題,所以牢記這一點,我選擇了他的答案作爲接受的答案,但無論如何非常非常感謝:) –

4

這被稱爲類陰影。

1.)這是可能的,因爲Java類不是靜態鏈接的,而是在類加載時鏈接的。

2.)如果不允許的話,那麼整個類的加載會更難實現。然後,例如,您還必須針對特定的Java版本構建項目。因爲Java類可能會因版本而異。這不會是一個可維護的方法。

3.)osgi利用它可以加載相同包的不同版本。另一個常見的用例是替換框架中的buggy類,其中沒有其他解決方法是可能的。但是,應該謹慎使用這種技術,因爲錯誤可能很難調試。

請注意,不能在java。*包中使用影子類,因爲這會破壞Java安全沙箱。所以你會在運行時遇到問題。