包本地类的类文本和 Class.forName 的不同行为



仅例如,让我们考虑sun.reflect包中的类ClassFileAssembler

此类是一个包本地类:

class ClassFileAssembler implements sun.reflect.ClassFileConstants {...

所以我们甚至不能使用它的名字ClassFileAssembler,我们不能直接导入它 - 这会导致编译器错误。

但是,我们可以在项目中创建一个名为 sun.reflect 的包,并在此包内部使用ClassFileAssembler名称 - Java 编译器会认为我们在ClassFileAssembler的包内。

如果是这样,为什么不尝试获取对类对象的引用,即 ClassFileAssembler.class

Class<ClassFileAssembler> classFileAssemblerClass = ClassFileAssembler.class;

意外地,此代码导致运行时错误:java.lang.IllegalAccessError: tried to access class sun.reflect.ClassFileAssembler from class sun.reflect.Test

但是我们仍然能够获取ClassFileAssembler类对象:

Class<ClassFileAssembler> aClass = (Class<ClassFileAssembler>)Class.forName("sun.reflect.ClassFileAssembler");

它工作正常,并为我们提供了完整的类描述。


所以,问题是:

1)技术之间有什么区别,Class.forName0如何检索对类对象的引用,以及它是如何.class的?

2)为什么他们有如此不同的安全检查?

3)以这种方式保护.class参考的原因是什么?

4) 这些技术是否使用不同的类加载器?

Class.forName 不关心类是否是本地包。 当您尝试使用该类时,将检查访问权限。 顺便说一句,如果你确实设置了可访问(true),你可以通过这些访问限制。

反射库允许您执行许多在 Java 代码中无法执行的操作。 Java 有关于你可以做什么和不能做什么的规则,例如,你不能在构造函数之外设置一个final字段或多次。 注意:JVM 没有此限制,在运行时,您可以使用反射来更改它。

此类是包本地的原因是限制类对此包外部代码的访问。 这并不意味着如果您真的尝试就无法访问它,但是如果没有认真考虑,您不太可能访问它。 例如,当我在 IDE 中导入类时,它通常会建议来自 com.sun.* 的类,这不太可能是正确的选择。(我的IDE可以设置为忽略这些,但我似乎经常找到一些我不想要的新包)

反射可以执行此操作的原因是支持序列化等功能。 使用序列化,您需要能够在序列化库的包之外序列化类,并在反序列化时获取字段并重置它们。 反射也被许多控制反转库使用,尽管我怀疑这不是他们在设计它时的想法。

如果你检查 Class#forName 的 javadoc ,你会看到:

请注意,此方法不检查其调用方是否可以访问所请求的类。

  1. 没有区别。但是您不能访问包私有(无修饰符)类.class的静态字段ClassFileAssembler
  2. 每个人都可以访问类实例,但字段受到保护。
  3. 事实上,没有人设计以保护.class以这种方式引用,这是保护其他领域的副作用。
  4. 我不这么认为。

相关内容

  • 没有找到相关文章

最新更新