简体   繁体   English

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

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

I am just playing with package structure. 我只是玩包结构。 And to my surprise I can bypass the default classes by creating my package and class name with that name. 令我惊讶的是,我可以通过使用该名称创建我的包和类名来绕过默认类。

For ex: 例如:

I created a package called java.lang and Class is Boolean . 我创建了一个名为java.lang的包,Class是Boolean When I import java.lang.Boolean it's not the JDK's version of Boolean . 当我导入java.lang.Boolean它不是JDK的Boolean版本。 It's mine. 这是我的。 It's just showing the methods of Objects which every object java have. 它只显示了每个对象java拥有的Objects的方法。

Why so ? 为什么这样 ? Why I am allowed to create the package java.lang ? 为什么我被允许创建java.lang包? And the program runs fine. 程序运行正常。

在此输入图像描述

Another baffle is if I create a Class with name Object and try to runs the program then an exception 另一个困惑是如果我创建一个名为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)

Why is this behaviour ? 为什么会这样? is this a bug or normal behaviour ? 这是一个错误还是正常行为?

The restriction on java.lang classes is a runtime restriction, not a compile time one. java.lang类的限制是运行时限制,而不是编译时限制。

The JVM actually specifically provides a mechanism for overriding classes in java.lang . JVM实际上特别提供了一种覆盖java.lang类的机制。 You can do it using the -Xbootclasspath command line flag : 您可以使用-Xbootclasspath命令行标志来执行此操作:

-Xbootclasspath:bootclasspath
Specifies a semicolon-separated list of directories, JAR files, and ZIP archives to search for boot class files. 指定以分号分隔的目录,JAR文件和ZIP存档列表,以搜索引导类文件。 These are used in place of the boot class files included in the Java platform JDK. 这些用于代替Java平台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. 不应部署使用此选项来覆盖rt.jar中的类的应用程序,因为这样做会违反Java Runtime Environment二进制代码许可证。

-Xbootclasspath/a:path
Specifies a semicolon-separated path of directories, JAR files, and ZIP archives to append to the default bootstrap class path. 指定以分号分隔的目录路径,JAR文件和ZIP存档,以附加到默认引导程序类路径。

-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. 指定要在默认引导程序类路径前添加的以分号分隔的目录,JAR文件和ZIP存档的路径。

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. 不要部署使用此选项的应用程序来覆盖rt.jar中的类,因为这违反了Java Runtime Environment二进制代码许可证。

However, as I've already emphasized with bold marks, doing so is a violation of the Oracle Binary Code License Agreement for Java SE and JavaFX Technologies : 但是,正如我已经用粗体标记强调的那样,这样做违反了Java SE和JavaFX技术Oracle二进制代码许可协议

D. JAVA TECHNOLOGY RESTRICTIONS. D. JAVA技术限制。 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. 您不得创建,修改或更改被许可方的行为,或授权其创建,修改或更改以任何方式标识为“java”,“javax”,“javax”的类,接口或子包的行为。 javafx“,”sun“,”oracle“或Oracle在任何命名约定中指定的类似约定。 You shall not redistribute the Software listed on Schedule 1. 您不得重新分发附表1中列出的软件。

Apart from the above, you may add whatever class you want to whatever packages you want ; 除了上述内容之外,您可以将任何您想要的课程添加到您想要的任何课程中 ; it's specifically discussed in the the JLS §13.3 : 它在JLS§13.3中有具体讨论:

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. 即使此处另有描述不兼容性,也可以删除或以其他方式更改此类型,前提是该包的受影响二进制文件一起更新。

Answer to SecurityException related question: 回答SecurityException相关问题:

SecurityManger throws this RuntimeException while your classloader calling defineClass method and encountered specified class(your "custom class") name has "java.*" in it. 当您的类加载器调用defineClass方法并遇到指定的类(您的“自定义类”)名称中包含“java。*”时,SecurityManger会抛出此RuntimeException。

This is because you defined your class in "java.*" package and as per ClassLoader's documentation this is not allowed. 这是因为您在“java。*”包中定义了您的类,并且根据ClassLoader的文档,这是不允许的。

defineClass( ) 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. 指定的名称不能以“java。”开头,因为“java。*包中的所有类只能由引导类加载器定义。如果name不为null,则它必须等于由指定的类的二进制名称。字节数组“b”,否则将抛出NoClassDefFoundError。

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.". SecurityException - 如果尝试将此类添加到包含由与此类不同的证书集签名的类的包,或者名称以“java。”开头。

For your testing, try creating java.test package and define one Custom class (names doesn't matter; like Object ..). 对于您的测试,尝试创建java.test包并定义一个Custom类(名称无关紧要;如Object ..)。 In this case as well you will get same SecurityException. 在这种情况下,您将获得相同的SecurityException。

package java.test;

public class Test {

    public static void main(String[] args) {

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

This is not Bug. 这不是Bug。

Behaviour beacause of: 行为因为:

When the Java Virtual Machine (JVM) tries to load our class, it recognizes its package name as invalid and thus, a SecurityException is thrown. 当Java虚拟机(JVM)尝试加载我们的类时,它会将其包名识别为无效,因此会抛出SecurityException。 The SecurityException indicates that a security violation has occurred an thus, the application cannot be executed. SecurityException表示发生了安全违规,因此无法执行应用程序。 public class SecurityException extends RuntimeException Thrown by the security manager to indicate a security violation. 公共类SecurityException扩展RuntimeException 由安全管理器抛出,以指示安全违规。

please use different package name it not for only language package of java.it covers all package not gives permissions to override in build classes and packages of java. 请使用不同的包名称,它不仅适用于java.it的语言包。所有包都没有赋予在java的构建类和包中覆盖的权限。

By Changing this we can create or override same package and 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 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"));

} }

Your problem with java.lang.Boolean as your Boolean Class, and not the Object one is simple to explain. 你的java.lang.Boolean作为你的布尔类,而不是对象的问题很容易解释。

The Object class is the root of every other classes you can find, use, or even create. Object类是您可以查找,使用甚至创建的每个其他类的根。 Which means that if you could have the ability to override it, not a single class, method, or whatever you want to use would work, since every of them depends on that root class. 这意味着如果你能够覆盖它,那么你可以使用一个类,方法或任何你想要使用的方法,因为每个类都依赖于那个根类。
For the Boolean Class, it is not a boolean type, but a class for a boolean type. 对于布尔类,它不是布尔类型,而是布尔类型的类。 And since nothing depends on it, it is then possible to override it. 并且由于没有任何依赖于它,因此可以覆盖它。
A better way to understand this problem, is to look at this link: 了解此问题的更好方法是查看此链接:
[ http://docs.oracle.com/javase/7/docs/api/overview-tree.html] [ http://docs.oracle.com/javase/7/docs/api/overview-tree.html]
You will notice that every kind of package, containing every kind of java classes, depends on the Object Class. 您会注意到,包含各种java类的每种包都依赖于Object Class。

So the security exception you encountered is like a "life savior" for your program. 因此,您遇到的安全例外就像是程序的“生命救星”。
If I'm wrong about your question, other persons may find a more appropriate answer to it. 如果我对你的问题不对,其他人可能会找到更恰当的答案。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM