我试图找到一种列出运行时对象所指对象的方法。我知道有一种方法可以使用oql查询jvm,但我想做的就是从程序内部查询它。我可以使用任何API吗?

最佳答案

您可以通过反射( java.lang.reflect )完成。

如何描述in this article。基本上,鉴于此类具有私人成员:

public class Secret {

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

    private String getSecretCode(){
        return secretCode;
    }
}

使用反射,您可以访问其所有成员(包括私有成员),包括其值。因此,您可以查看其所有数据成员以查看它们所引用的内容(当然,如果它们也引用其他对象,则可以重复该过程)。这是访问其成员的方法(此代码还显示了方法,如果您只对数据感兴趣,可能不需要这些方法,但是我没有看到将其取出的任何充分理由):
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();
        }
    }
}

我已经修复了原始代码中的一个错误,并做了一些小的更改,以使更加清楚,HackerSecret无关(而不是main)。

更新:下面是有关基类中字段的问题,这是一个更新的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();
        }
    }
}

当与
public class BaseSecret {

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

}


public class Secret extends BaseSecret {

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

    private String getSecretCode(){
        return secretCode;
    }
}

你得到:

$ java黑客
上课时:秘密
访问所有方法
方法名称:getSecretCode
返回类型:类java.lang.String
这是秘密

进入所有领域
字段名称:secretCode
这是秘密

来自 class :BaseSecret
访问所有方法
进入所有领域
字段名称:baseSecretCode
这是一个基本秘密

10-05 18:07
查看更多