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

时间:2013-01-25 09:15:31

标签: java reflection class-visibility

仅举例来说,我们可以考虑来自ClassFileAssembler包的课程sun.reflect

这个类是一个包本地类:

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)这些技术是否使用不同的类加载器?

3 个答案:

答案 0 :(得分:3)

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

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

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

Reflection可以做到这一点的原因是支持序列化等功能。使用序列化,您需要能够在序列化库的包外部序列化类并获取字段并在反序列化时重置它们。许多Inversion of Control库也使用了反射,但我怀疑这不是他们设计时想到的。

答案 1 :(得分:2)

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

  

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

答案 2 :(得分:0)

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