简体   繁体   English

如何找到对象所指的内容?

[英]How do I find what an object refers to?

I'm trying to find a way to list which objects a run-time object is referring to. 我正在尝试找到一种方法来列出运行时对象所引用的对象。 I know there is a way to enquire the jvm using oql but what I'd like to do is to query it from inside a program. 我知道有一种方法可以使用oql查询jvm,但我想做的是从程序内部查询它。 Is there any API I could use? 我可以使用任何API吗?

You can do it via Reflection ( java.lang.reflect ). 你可以通过Reflection( java.lang.reflect )来做到这一点。

How is described in this article . 如何在本文中描述。 Basically, given this class that has private members: 基本上,鉴于此类具有私有成员:

public class Secret {

    private String secretCode = "It's a secret";

    private String getSecretCode(){
        return secretCode;     
    }
}

With Reflection, you can access all of its members (including the private ones), including their values. 使用Reflection,您可以访问其所有成员(包括私有成员),包括其值。 And so you look at all of its data members to see what they refer to (and of course, you can repeat the process if they also refer to other objects). 因此,您查看其所有数据成员以查看它们所引用的内容(当然,如果它们也引用其他对象,则可以重复该过程)。 Here's how to access their members (this code shows methods as well, which you probably won't need if you're just interested in data, but I didn't see any good reason to pull that part out): 以下是访问其成员的方法(此代码也显示了方法,如果您只是对数据感兴趣,则可能不需要这些方法,但我认为没有任何理由将其拉出来):

import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
import java.lang.reflect.InvocationTargetException; 

public class Hacker {

    private static final Object[] EMPTY = {};

    public void reflect(Object instance)
    throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class secretClass = instance.getClass();

        // Print all the method names & execution result
        Method methods[] = secretClass.getDeclaredMethods(); 
        System.out.println("Access all the methods"); 
        for (int i = 0; i < methods.length; i++) { 
            System.out.println("Method Name: " + methods[i].getName());
            System.out.println("Return type: " + methods[i].getReturnType());
            methods[i].setAccessible(true);
            System.out.println(methods[i].invoke(instance, EMPTY) + "\n");
        }

        //  Print all the field names & values
        Field fields[] = secretClass.getDeclaredFields();
        System.out.println("Access all the fields");
        for (int i = 0; i < fields.length; i++){ 
            System.out.println("Field Name: " + fields[i].getName()); 
            fields[i].setAccessible(true); 
            System.out.println(fields[i].get(instance) + "\n"); 
        }
    }

    public static void main(String[] args){

        Hacker newHacker = new Hacker();

        try { 
            newHacker.reflect(new Secret());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

I've fixed a bug in their original code and made a small change to make it more clear that Hacker is not in any way tied to Secret (other than in main ). 我修复了他们原始代码中的一个错误并进行了一些小改动,以便更清楚地表明HackerSecret (除了main )没有任何关系。

Update : Re your question below about the fields from base classes, here's an updated Hacker that does that (I've assumed you don't want to try to enumerate the fields on Object , so I've stopped there): 更新 :回答下面关于基类字段的问题,这里有一个更新的Hacker (我假设你不想尝试枚举Object上的字段,所以我已经停在那里):

import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
import java.lang.reflect.InvocationTargetException; 

public class Hacker {

    private static final Object[] EMPTY = {};

    public void reflect(Object instance)
    throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class cls = instance.getClass();

        while (cls != null && cls != Object.class) {
            System.out.println("From class: " + cls.getName());

            // Print all the method names & execution result
            Method methods[] = cls.getDeclaredMethods(); 
            System.out.println("Access all the methods"); 
            for (int i = 0; i < methods.length; i++) { 
                System.out.println("Method Name: " + methods[i].getName());
                System.out.println("Return type: " + methods[i].getReturnType());
                methods[i].setAccessible(true);
                System.out.println(methods[i].invoke(instance, EMPTY) + "\n");
            }

            //  Print all the field names & values
            Field fields[] = cls.getDeclaredFields();
            System.out.println("Access all the fields");
            for (int i = 0; i < fields.length; i++){ 
                System.out.println("Field Name: " + fields[i].getName()); 
                fields[i].setAccessible(true); 
                System.out.println(fields[i].get(instance) + "\n"); 
            }

            // Go to the base class
            cls = cls.getSuperclass();
        }
    }

    public static void main(String[] args){

        Hacker newHacker = new Hacker();

        try { 
            newHacker.reflect(new Secret());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

When combined with 与...结合使用时

public class BaseSecret {

  private String baseSecretCode = "It's a base secret";

}

and

public class Secret extends BaseSecret {

    private String secretCode = "It's a secret";

    private String getSecretCode(){
        return secretCode;     
    }
}

you get: 你得到:

$ java Hacker 
From class: Secret
Access all the methods
Method Name: getSecretCode
Return type: class java.lang.String
It's a secret

Access all the fields
Field Name: secretCode
It's a secret

From class: BaseSecret
Access all the methods
Access all the fields
Field Name: baseSecretCode
It's a base secret

您可以使用Object类的getClass()方法来获取对象的运行时类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM