JVM如何判断一个类(例如内部或嵌套类)是否“属于”另一个类?

7

我想更好地了解类文件和内部/嵌套类,以下是我的疑问:

  • InnerClasses属性是用于引用´包含´类中的内部/嵌套类还是在内部/嵌套类中用于引用‘容器’类?
  • 类文件中的InnerClasses属性是否足够? 例如,内部/嵌套类是否必须遵循$名称编码?这只是一种约定吗?
  • 是否有一种方法可以使类看起来像JVM的内部/嵌套类,而不设置InnerClasses属性?这取决于JLM供应商吗?(我记得听说IBM的实现在某些部分的要求较少。)
  • JVM的类加载机制与Java反射有多大交互?是否可能使JVM与Java反射的结果不同?

我试图在JVM规范中查找,但没有找到实际机制的描述。

“The InnerClasses Attribute”中,我仅发现与我的问题相关联的这句话:

The Java虚拟机当前不检查InnerClasses属性与任何由该属性引用的类或接口实际表示的类文件的一致性。


1
在阅读了您下面的评论后,我决定不回答您的问题。我只是留下这个评论,向您指出当您请求帮助时,您下面的互动方式可能不是与这个社区互动的最佳方式。 - philwb
谢谢您的赞美之词。我认为回答“你为什么想知道?”是居高临下的,不适合在这个社区中,但您可能有不同的看法。 - soc
2个回答

2
上一篇回答的一些补充内容:
每个编译的类的字节码都存储在单独的 .class 文件中。实际的"内部类"并未存储在 InnerClasses 属性中。正如上一个帖子指出的那样,该属性仅指向编译器在创建字节码时知道的类。
对于这两个问题,我不确定。但我认为内部/嵌套类的概念是 Java 语言(因此是 Java 编译器提供的)。在字节码中,应该没有任何一个声明为普通公共类和某些嵌套或内部类之间的区别。您可以轻松尝试测试一个给定虚拟机如何处理这个问题:
- 创建一个带有一些嵌套和内部类的类 - 编写一个小程序,尝试通过反射从定义类的范围外加载和实例化其中一个内部类。您必须在这里使用反射,因为 Java 编译器不允许您实例化不在作用域内的嵌套类! 如果您可以成功地实例化该类,则表明在内部,VM 并未以不同方式处理嵌套和普通类。
关于最后一个问题“JVM 的类加载机制与 Java 反射交互有多少?使 JVM 不同意 Java 反射的结果是否可能?”我不理解。您可以解释一下当您说 VM 和反射应该意见不合时,您的意思是什么吗?

你好Jochen!
  1. 我在想InnerClass属性的方向,例如它是从内部类指向包含类还是反过来?
  2. 我问这个问题是因为规范中似乎没有明确说明。我会按照你的建议进行测试。
- soc
  1. JVM的“自有”ClassLoader是用本地代码实现的,而涉及类的反射功能则是用Java实现的,主要是通过比较和子字符串处理字符串来实现的。我想知道是否可能制作一个文件,使JVM的机制与Java反射不一致。例如,Java反射表示A$BA的内部类,而JVM则表示不是。
- soc
我快速查看了一下,似乎BOTH都设置了InnerClasses属性。你可以使用Eclipse内置的Class File Viewer(右键单击.class文件并选择“Open with -> Class File Viewer”)查看生成的字节码。那里写的信息告诉你哪个是外层类,哪个是内部类。所以如果有人(例如类加载器)查看,它可以从那里推断出来。 然而,我怀疑这可能是不同编译器做法不同的事情。我只检查过Eclipse/JDT。 - Jochen
对于最后一个问题,我不确定,我在反射方面不是很擅长,但这是我的看法。 1)任何类加载器都会初始化描述它正在加载的类的许多内部数据结构。这包括您可以通过反射访问的元类(Class、Method、Constructor等)。 2)我相信您可以构建一个忽略有关内部类信息的类加载器,从而创建一个看起来与默认类加载器构建的类不同的类。 - Jochen
然而,这与反射完全无关。反射始终会告诉您内部数据结构包含什么,最终由使用的类加载器定义。由于我对此了解不够,建议您尝试黑客攻击某些东西,以删除InnerClasses属性,然后加载类。看看是否可以直接实例化内部类。 - Jochen
太好了!非常感谢。你能把你在评论中提供的信息放到回答里吗?这样其他人就更容易阅读了。有时候SO会折叠重要的评论。 :-) - soc

1
我知道类文件中有一个内部类属性,但这是否足够呢?
InnerClasses 属性在字节码中,它列出了外部类的所有已知内部类。这不是您可以直接使用的。
例如,内部/嵌套类是否必须遵循带有 $ 的名称混淆,还是这只是一种约定?
编译器将遵循此约定,您无法控制它。
是否有一种方法使类看起来像是 JVM 中的内部/嵌套类,而不设置内部类属性,这是否取决于 JLM 供应商?(我记得听说 IBM 的实现在某些方面要求不那么严格。)
您可以创建一个同名的类。您可以自己尝试一下。
JVM 的类加载机制与 Java 反射交互多少?
我不认为类加载器使用反射。但是,反射可能从类加载器获取其信息。我不明白为什么会有影响。
是否可能使 JVM 对 Java 反射的结果持不同意见?

您可以使用反射来破坏基于反射的对象中的数据。但是,不确定为什么您想要这样做。


1
也许你可以更具体地说明你想要知道什么,比如为什么你需要知道这个? - Peter Lawrey
不仅是我的看法,甚至规范也指出它是一个被忽略的细节。 - Peter Lawrey
与其从头开始编写,我宁愿使用现有的开源编译器,并仅修改感兴趣的部分。编写自己的编译器或修改现有编译器的问题在于它们会不时地得到漏洞修复并很快变得过时。更为强大的方法是创建一个字节码操纵器,该操纵器在编译器之后运行以执行您需要执行的任何操作。这种方法被许多字节码操作库所使用,并且可以与来自不同供应商的多个版本的javac一起使用。 - Peter Lawrey
1
Haskell有内部类吗?鉴于InnerClasses未被检查,它是否具备内部类并不重要,你可以选择设置或不设置。 - Peter Lawrey
1
我相信这个实习生确信自己做得很好,也完成了任务。http://thedailywtf.com/Articles/TwentyFour-Bits-Per-Intern.aspx 我认为你需要阅读这篇文章http://c2.com/xp/YouArentGonnaNeedIt.html,否则你可能会浪费时间。 - Peter Lawrey
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接