【问题标题】:A custom String class creation自定义 String 类创建
【发布时间】:2012-12-29 05:56:57
【问题描述】:

我试图在我的 Eclipse 工作区的 java.lang 包中创建一个自定义类 String。 最初我怀疑不能在同一个包中创建同一个类,但令我惊讶的是,我能够在同一个包中创建一个类(字符串),即 java.lang

现在我很困惑
1)为什么可能和
2)如果允许,可能是什么原因。
3) 如果在 Java 中允许这种类型的 java 类创建,会有什么用。

【问题讨论】:

  • 如果没记错的话,java.lang 包是sealed,所以你不能向它添加成员。如果在运行时 jar 中替换 String 类型会成功,我会感到惊讶,因为该类型对 JVM 的操作非常重要。

标签: java string class final


【解决方案1】:

您可以在 java.lang 包中创建一个新类。如果禁止 Oracle 开发人员如何开发 Java?我相信他们使用的 javac 和我们一样。

但是您将无法加载它,因为 java.lang.ClassLoader(任何类加载器都扩展)不允许它,每个正在加载的类都经过此检查

...
        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 这样隐藏现有类的类,它们无法加载,因为系统类加载器(默认)使用“父优先”策略,因此 java.lang 类将使用引导类加载器从 rt.jar 加载。因此,您需要将 rt.jar 中的 String.class 替换为您的版本。或者使用-Xbootclasspath/p: java 选项覆盖它,该选项将路径添加到引导类加载器搜索路径。所以你可以

1) 将真实的 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

【讨论】:

  • 这个答案如何回答 OP 指出的 3 个问题?
【解决方案2】:

这称为类阴影。

1.) 这是可能的,因为 java 类不是静态链接的,而是在类加载时链接的。

2.) 如果不允许,那么整个类的加载将很难实现。然后,例如,您还必须针对特定的 Java 版本构建项目。因为 Java 类可能会因版本而异。这不会是一种可维护的方法。

3.) osgi 利用它来加载同一包的不同版本。另一个常见的用例是替换框架中的错误类,在这种情况下没有其他解决方法是可能的。但是,应该谨慎使用这种技术,因为错误可能很难调试。

请注意,不允许在 java.* 包中隐藏类,因为这会破坏 Java 安全沙箱。所以你会在运行时遇到问题。

【讨论】:

    【解决方案3】:

    是的,您可以创建名称为 java.lang 的包以及命名为 String 的类。

    但是你不能运行你的 String 类。

    1) 为什么会这样:编译器会成功编译你的类。

    2) 如果允许,可能是什么原因:你的包和类有一个有效的名称,所以编译器不会抱怨。

    3) 如果在 Java 中允许这种类型的 java 类创建会有什么用: 但是这个 String 类没有太多用处。 Bootstrap 类加载器将从 sun 的 java.lang 包中加载类。因此您的自定义 String 类将不会被加载,因此在运行期间会失败。

    Bootstrap 类加载器是 JVM 实现的一部分,它加载 Java API 的类(包括 java.lang.String)。同样对于每个被加载的类,JVM 会跟踪哪个类加载器是引导程序还是用户定义的加载类。因此,任何加载自定义 String 类的尝试都会失败,因为 String 类已经加载。

    【讨论】:

    • 你应该解释他为什么不能跑。
    • 感谢 rai.sKumar,如果我有两种选择答案,我肯定会选择这个作为第二好的答案。因为它是清晰、准确和中肯的答案。但是 Evgeniy Dorofeev 选择的答案是这样的(bcoz of code),即使是外行也可以理解和模拟问题,所以记住这一点,我选择他的答案作为接受的答案,但无论如何非常非常感谢 :)
    猜你喜欢
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 2015-10-20
    • 2011-06-23
    相关资源
    最近更新 更多