【问题标题】:Different behaviour of Class literal and Class.forName for package local classes包本地类的类文字和 Class.forName 的不同行为
【发布时间】:2013-01-09 05:33:40
【问题描述】:

仅作为示例,让我们考虑 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("sun.reflect.ClassFileAssembler") 调用该类中的静态初始化程序,如果您将 true 作为第二个参数传递给方法,但不调用构造函数,也不调用 .main 方法。

标签: java reflection class-visibility


【解决方案1】:

Class.forName 不关心一个类是否是本地包。正是当您尝试使用该类时,才会检查访问。顺便说一句,如果你执行 setAccessible(true),你可以绕过这些访问限制。

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

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

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

【讨论】:

  • 感谢您的回复,彼得。我想知道,setAccesibile 是什么对象?对于Class 对象?
  • 对于此类的所有成员。
  • 是的,我知道会员。那么类对象呢?
  • 类对象只是 JVM 中底层数据结构的代理。拿着Class 不允许你用它做任何特别的事情。我相信.class不允许的唯一原因是为了符合Java的访问规则。
【解决方案2】:

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

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

【讨论】:

  • 非常感谢。我只是错过了javadoc 关于支票的描述。
【解决方案3】:
  1. 没有区别。但是你不能访问包私有(无修饰符)类ClassFileAssembler的静态字段.class
  2. 每个人都可以访问 Class 实例,但字段是受保护的。
  3. 事实上,没有人设计来保护.class 这样引用,这是保护其他字段的副作用。
  4. 我不这么认为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    相关资源
    最近更新 更多