2013-01-15 216 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安全沙箱。所以你会在运行时遇到问题。