为什么我能够重新创建 java.lang 包和 类?

Why I am able to re-create java.lang package and classes?

我只是在玩包结构。令我惊讶的是,我可以通过创建我的包和使用该名称的 class 名称来绕过默认的 classes。

例如:

我创建了一个名为 java.lang 的包,Class 是 Boolean。当我导入 java.lang.Boolean 时,它不是 JDK 版本的 Boolean。这是我的。它只是显示每个对象 java 具有的 Objects 的方法。

为什么会这样?为什么允许我创建包 java.lang?程序运行良好。

另一个问题是,如果我创建一个名称为 ObjectClass 并尝试运行该程序,然后出现异常

java.lang.SecurityException: Prohibited package name: java.lang
    at java.lang.ClassLoader.preDefineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)

为什么会出现这种行为?这是错误还是正常行为?

SecurityException 相关问题的答案:

SecurityManger 在您的 classloader 调用 defineClass 方法并遇到指定的 class(您的 "custom class")名称中包含 "java.*" 时抛出此 RuntimeException。

这是因为您在 "java.*" 包中定义了 class,并且根据 ClassLoader's documentation 这是不允许的。

defineClass( )

..

The specified name cannot begin with "java.", since all classes in the "java.* packages can only be defined by the bootstrap class loader. If name is not null, it must be equal to the binary name of the class specified by the byte array "b", otherwise a NoClassDefFoundError will be thrown.

Throws: ..

SecurityException - If an attempt is made to add this class to a package that contains classes that were signed by a different set of certificates than this class, or if name begins with "java.".

为了您的测试,请尝试创建 java.test 包并定义一个自定义 class(名称无关紧要;例如 Object..)。在这种情况下,您也会得到相同的 SecurityException。

package java.test;

public class Test {

    public static void main(String[] args) {

        System.out.println("This is Test");
    }
}

java.lang classes 的限制是运行时限制,而不是编译时限制。

JVM其实专门提供了覆盖java.lang中classes的机制。您可以使用 -Xbootclasspath command line flag:

-Xbootclasspath:bootclasspath
Specifies a semicolon-separated list of directories, JAR files, and ZIP archives to search for boot class files. These are used in place of the boot class files included in the Java platform JDK.

Applications that use this option for the purpose of overriding a class in rt.jar should not be deployed because doing so would contravene the Java Runtime Environment binary code license.

-Xbootclasspath/a:path
Specifies a semicolon-separated path of directories, JAR files, and ZIP archives to append to the default bootstrap class path.

-Xbootclasspath/p:path
Specifies a semicolon-separated path of directories, JAR files, and ZIP archives to add in front of the default bootstrap class path.

Do not deploy applications that use this option to override a class in rt.jar because this violates the Java Runtime Environment binary code license.

但是,正如我已经用粗体标记强调的那样,这样做违反了 Oracle Binary Code License Agreement for Java SE and JavaFX Technologies:

D. JAVA TECHNOLOGY RESTRICTIONS. You may not create, modify, or change the behavior of, or authorize your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "javafx", "sun", “oracle” or similar convention as specified by Oracle in any naming convention designation. You shall not redistribute the Software listed on Schedule 1.

除上述之外,您可以将任何class添加到您想要的任何包;它在 JLS §13.3:

中具体讨论

13.3. Evolution of Packages

A new top level class or interface type may be added to a package without breaking compatibility with pre-existing binaries, provided the new type does not reuse a name previously given to an unrelated type.

If a new type reuses a name previously given to an unrelated type, then a conflict may result, since binaries for both types could not be loaded by the same class loader.

Changes in top level class and interface types that are not public and that are not a superclass or superinterface, respectively, of a public type, affect only types within the package in which they are declared. Such types may be deleted or otherwise changed, even if incompatibilities are otherwise described here, provided that the affected binaries of that package are updated together.

您将 java.lang.Boolean 作为布尔值 Class 而不是对象一的问题很容易解释。

对象 class 是您可以找到、使用甚至创建的所有其他 classes 的根。这意味着如果你有能力覆盖它,那么单个 class、方法或任何你想使用的方法都不会起作用,因为它们中的每一个都依赖于根 class.
对于booleanClass,不是boolean类型,而是boolean类型的class。由于没有任何依赖它,因此可以覆盖它。
理解这个问题的更好方法是看这个 link:
[http://docs.oracle.com/javase/7/docs/api/overview-tree.html]
你会注意到每一种包,包含每一种 java classes,取决于对象 Class.

所以你遇到的安全异常就像是你程序的"life savior"。
如果我对你的问题有误,其他人可能会找到更合适的答案。 :)

这不是 Bug。

行为原因:

当 Java 虚拟机 (JVM) 尝试加载我们的 class 时,它会将其包名称识别为无效,因此抛出 SecurityException。 SecurityException 表示发生安全违规,因此无法执行应用程序。 public class 安全异常 扩展 RuntimeException 由安全管理器抛出以指示安全违规。

请使用不同的包名称,它不仅适用于 java.it 的语言包,还涵盖所有未授予在构建 classes 和 java.[=11 的包中覆盖的权限的包=]

通过改变这个我们可以创建或覆盖相同的包和 class:

a/j2ee.core.utilities/src/org/netbeans/modules/j2ee/core/api/support/java/JavaIdentifiers.java b/j2ee.core.utilities/src/org/netbeans/modules/j2ee/core/api/support/java/JavaIdentifiers.java

**if (packageName.startsWith(".") || packageName.endsWith(".")) {// NOI18N
          return false;
        }

   if(packageName.equals("java") || packageName.startsWith("java.")) {//NOI18N
          return false;
      }**

    String[] tokens = packageName.split("\."); //NOI18N
       if (tokens.length == 0) {
          return Utilities.isJavaIdentifier(packageName);
 a/j2ee.core.utilities/test/unit/src/org/netbeans/modules/j2ee/core/api/support/java/JavaIdentifiersTest.java    b/j2ee.core.utilities/test/unit/src/org/netbeans/modules/j2ee/core/api/support/java/JavaIdentifiersTest.java

      assertFalse(JavaIdentifiers.isValidPackageName(" "));
      assertFalse(JavaIdentifiers.isValidPackageName("public"));
      assertFalse(JavaIdentifiers.isValidPackageName("int"));
      assertFalse(JavaIdentifiers.isValidPackageName("java"));
      assertFalse(JavaIdentifiers.isValidPackageName("java.something"));

}