【问题标题】:Java & Javap: How to Determine Which Object Receives InvokevirtualJava & Javap:如何确定哪个对象接收 Invokevirtual
【发布时间】:2014-10-21 23:47:52
【问题描述】:

我正在查看 Javap 的输出。例如:

这段代码

    final Foo foo = new Foo(1,2);
    ... 
    new Callable<Integer>()
    {
        @Override
        public Integer call() throws Exception
        {
            return foo.doSomething();
        }

生成:

        jvmOperations": [{
            "byteOffset": 0,
            "constantPoolIndex": null,
            "opCode": 42,
            "opCodeName": "aload_0",
            "type": null,
            "tagName": null,
            "tagValue": null
        }, {
            "byteOffset": 1,
            "constantPoolIndex": null,
            "opCode": 180,
            "opCodeName": "getfield",
            "type": null,
            "tagName": "Field",
            "tagValue": "val$foo:Lcom/example/graph/demo/Foo;"
        }, {
            "byteOffset": 4,
            "constantPoolIndex": null,
            "opCode": 182,
            "opCodeName": "invokevirtual",
            "type": null,
            "tagName": "Method",
            "tagValue": "com/example/graph/demo/Foo.doSomething:()Ljava/lang/Integer;"
        }, {
            "byteOffset": 7,
            "constantPoolIndex": null,
            "opCode": 176,
            "opCodeName": "areturn",
            "type": null,
            "tagName": null,
            "tagValue": null
        }]

所以我看到在这种情况下该对象由val$foo 标识。而在类元数据中

    "classMetaData": {
        "classId": "com/example/Main$1.class",
        "sourceName": "Main.java",
        "isInterface": false,
        "isClass": true,
        "accessModifiers": ["final"],
        "superClassName": "java/lang/Object",
        "implementedInterfaces": ["java/util/concurrent/Callable"],
        "jreTargetVersion": "51.0",
        "fields": ["val$foo"],
        "fieldModifiers": {
            "val$foo": ["final"]
        },
        "methodInformationMap": {},
        "interface": false,
        "class": true
    }, 

但现在我想了解更多关于原始对象foo 的信息。例如,我知道它在其中一个字段中有这些数据:

        {
            "byteOffset": 37,
            "constantPoolIndex": null,
            "opCode": 18,
            "opCodeName": "ldc",
            "type": null,
            "tagName": "String",
            "tagValue": "NODE-1"
        }, 

JVM如何知道val$foo指向什么?

【问题讨论】:

  • JVM 知道 val$foo 指向一个 Foo 对象(或 Foo 的某个子类),因为这是声明它的方式。而实际调用的方法取决于invokevirtual实际使用的对象的类。

标签: java opcode javap


【解决方案1】:

您需要更多上下文来跟踪 JVM 为 foo 存储的值。

假设foo是一个局部变量

  1. new Foo(1,2); 被调用
  2. 结果,实例引用的值,被复制并存储在局部变量foo
  3. ...东西...
  4. 调用匿名类构造函数来创建新实例
  5. 作为其构造函数的一部分,会检索局部变量 foo 的值的副本并将其压入堆栈
  6. 该值从堆栈中弹出并分配给匿名类的 val$foo 字段(这是关闭该变量)
  7. ...东西...
  8. foo.something()被调用时,JVM获取匿名类实例的val$foo字段的值
  9. JVM 取消引用该值以获取对象并调用其上的方法

【讨论】:

  • 感谢 Sotirios,事实证明我需要的部分数据也可能在常量池中。
猜你喜欢
  • 2012-02-06
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 2018-02-09
  • 2015-10-09
  • 1970-01-01
  • 2015-08-19
  • 1970-01-01
相关资源
最近更新 更多