2

我在 Java 字节码规范中发现了一些我不理解的东西。

考虑以下类层次结构:

class FilterOutputStream {
  protected OutputStream out;
}

class PrintStream extends FilterOutputStream {
  public void write(...) {
    out.write(...);
  }
}

用 javap 查看 PrintStream 的字节码,我看到读取out字段是这样完成的:

getfield #21

正如预期的那样,参考#21 是一个字段参考,包含该字段的类、名称和描述符。但是,它看起来像这样:

const #21 = Field #30.#204; //  java/io/PrintStream.out:Ljava/io/OutputStream;

这真是令人费解,因为这表明该out字段是 PrintStream 的成员。这不是真的; 它是FilterOutputStream 的成员,这是我希望在上面的字段参考中看到的类。JVM 规范非常模糊,但似乎支持我:

class_index 项的值必须是 constant_pool 表的有效索引。该索引处的 constant_pool 条目必须是 CONSTANT_Class_info(第 4.4.1 节)结构,表示具有字段或方法作为成员的类或接口类型。

(来自http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.2。)

这对我来说是个问题,因为我查看字段引用,加载类,然后找不到字段。另一方面,Java 编译器确实可以工作,所以我的理解显然是错误的......

有人可以为我澄清一下吗?我是否应该加载类,查找字段引用,如果找不到,则开始处理类层次结构,直到找到它?

指向规范的指针,指向它描述这样做的正确行为的地方将不胜感激......

4

1 回答 1

2

您错过了 JVM 规范中关于字段查找的部分。如果当前类中不存在该字段,则开始搜索超类和接口。

5.4.3.2 Field Resolution
To resolve an unresolved symbolic reference from D to a field in a class or interface
C, the symbolic reference to C given by the field reference must first be resolved
(§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of
resolution of a class or interface reference can be thrown as a result of field
resolution. If the reference to C can be successfully resolved, an exception relating
to the failure of resolution of the field reference itself can be thrown.
When resolving a field reference, field resolution first attempts to look up the
referenced field in C and its superclasses:
1. If C declares a field with the name and descriptor specified by the field
reference, field lookup succeeds. The declared field is the result of the field
lookup.
2. Otherwise, field lookup is applied recursively to the direct superinterfaces of
the specified class or interface C.
3. Otherwise, if C has a superclass S, field lookup is applied recursively to S.
4. Otherwise, field lookup fails.
于 2013-10-08T00:53:42.013 回答