“Example.class”指向的对象何时出现?

When does object pointed by 'Example.class' come into existence?

提问人:overexchange 提问时间:7/3/2015 最后编辑:overexchange 更新时间:7/3/2015 访问量:644

问:

以下是程序:

package annotationtype;

public class Example {

    public static void main(String[] args){

    }
}

使用以下字节码进行编译。

Classfile /D:/git/Java_programming/JavaCode/bin/annotationtype/Example.class
  ......
  Compiled from "Example.java"
public class annotationtype.Example
  .......
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // annotationtype/Example
   #2 = Utf8               annotationtype/Example
   #3 = Class              #4             // java/lang/Object
   ......
  #18 = Utf8               SourceFile
  #19 = Utf8               Example.java
{
  public annotationtype.Example();
  ........
  public static void main(java.lang.String[]);
  ......
}
SourceFile: "Example.java"

使用eclipse编辑器,在方法中,如果我键入,main()

Example.,eclipse 编辑器会立即提供classClass<annotationtype.Example>

我的理解是,

在字节码下方,

#1 = Class              #2             // annotationtype/Example
 ..
#3 = Class              #4             // java/lang/Object

表示在 的初始化阶段创建成员指向的类型的对象,这在功能上等同于:Class<annotationtype.Example>Class<annotationtype.Example> classclass Example

public class annotationtype.Example{
    public static Class<annotationtype.Example> class;
    {
        class = Class.forName("annotationtype.Example")
    }
    ......
}

我的理解正确吗,

类型的对象(创建)出现的阶段,即 ?Class<annotationtype.Example>Example.class

Java Eclipse

评论

5赞 Holger 7/3/2015
没有名为“class”的成员

答:

11赞 Holger 7/3/2015 #1

您将 Java 编程语言的工件与保存 Java 字节码的类文件的常量池中的项混淆了。

表单的类文字,以及对表单数组长度的访问,在源代码中可能看起来像成员访问,但与真正的类成员无关。type.classarray.length

例如,当你编写 时,它将被编译成一个字节码指令,专门用于在运行时检索数组的长度,而实际上没有指定 JVM 如何记住数组的长度。这取决于实现。array.lengtharraylength

类文本更为复杂。例如,当你编写 时,没有什么可查询的。相反,编译器知道它必须读取字段才能获取运行时值,这就是此类文字的编译方式,作为对 .相比之下,引用类型的类文字是使用指向常量池条目的指令编译的,该常量池条目与字段无关。int.classstaticInteger.TYPEInteger.TYPEldc

类的常量池首先不包含 Java 对象。它包含链接信息。某些条目在首次使用时可能会与 Java 运行时实例相关联,但其工作方式是有意未指定的。这取决于 JVM。这些条目有不同的用途,即 Class 条目可用于指定超类、实现的接口或类,其成员可通过方法调用或字段访问进行访问。

这就是您的类文件包含此类类条目的原因。它之所以存在,是因为类用它来描述自己。即使根本没有类文字。因此,在加载类时会创建一个描述类的实例。A 会记住所有加载的类,当使用相同的加载器解析相同的名称时,将使用它们。ExampleExample.classClassExampleClassLoader

请注意,当另一个类包含 形式的类文字时,它将在其自己的常量池中为该类提供自己的 Class 条目。类文本的运行时计算可能会触发加载,从而在之前未加载实例时创建实例。否则,它将通过类加载器解析为已加载的类。Example.classClass

评论

0赞 Holger 7/6/2015
对于基元类型,名称可以工作。但是引用类型由名称运行时的启动类装入器组成。正如我在回答中所说,类加载器会记住在其上定义的所有类,并将相同的名称解析为相同的实例,但不同的类加载器可能会定义具有相同名称的不同运行时类。因此,名称可能是模棱两可的。换句话说,如果源是 .但是,在不同的上下文中调用和解析它可能会产生不同的类。ClassClass.forNamegetConstructorStringClass.getName()
0赞 overexchange 7/7/2015
@Holger我没有得到这样的陈述:“类加载器会记住在其上定义的所有类,并将相同的名称解析为相同的类实例,但是不同的类加载器可能会定义具有相同名称的不同运行时类。所以一个名字可以是模棱两可的“,不同的运行时类具有相同的名称
0赞 Holger 7/7/2015
是的,在运行时,可以有多个具有相同名称的类。这取决于 s。比较 JVMS §5.3:“在运行时,类或接口不是仅由其名称确定,而是由一对确定:其二进制名称 (§4.2.1) 及其定义的类加载器。另见 JLS §12.2ClassLoader
0赞 Holger 7/9/2015
不要仅仅因为它们具有相同的名称就假定命名的两个类是相同的。它们可能派生自同一个类文件,但也有可能它们是进化类的不同版本,或者它们根本不相关。像OSGi这样的框架可能会在不同的加载器中多次加载未导出的类型,以确保捆绑包是解耦的。此外,卸载捆绑包以加载更新版本正是以这种方式工作的,有大量的动态框架在这样做。只要旧加载程序没有垃圾回收,这两个版本都会在运行时存在。X