有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用反射来调用公共方法

我正在编写一个API,在使用反射时遇到了一个问题。我要做的是从自定义对象类调用一个方法,并将值返回到调用的位置。调用的开始发生在main活动中。爪哇

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ByteMe b = new ByteMe();

        ExampleObject object = new ExampleObject("Bob", 20, "indy", "male", "its bobby");
        try {
            b.examine(object);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

我的示例对象类旨在帮助确保该API正常工作

public class ExampleObject {

    private String Name;
    private int Age;
    private String Location;
    private String Sex;
    private String Description;

    /**
     * Empty Constructor
     */
    public ExampleObject() {}

    /**
     * Basic constructor with initializing data
     *
     * @param _Name String with the name of the user
     * @param _Age Integer with the age of the user
     * @param _Location String containing the curret city and state of the user
     * @param _Sex String Male, Female, Transgender, or Other
     * @param _Description String short blurb about the user
     */
    public ExampleObject(String _Name, int _Age, String _Location, String _Sex, String _Description)
    {
        this.setName(_Name);
        this.setAge(_Age);
        this.setLocation(_Location);
        this.setSex(_Sex);
        this.setDescription(_Description);
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public int getAge() {
        return Age;
    }

    public void setAge(int age) {
        Age = age;
    }

    public String getLocation() {
        return Location;
    }

    public void setLocation(String location) {
        Location = location;
    }

    public String getSex() {
        return Sex;
    }

    public void setSex(String sex) {
        Sex = sex;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        Description = description;
    }
}

现在我面临的主要问题是,当我在另一个名为ByteMe的文件中调用时。爪哇:

public void examine(Object obj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        //Get the list of possible methods held in this object.
        Method[] methods = obj.getClass().getMethods();

        // iterate through them
        for (Method method : methods) {
            Log.d("" + this.getClass().getName(), "--------------------------");
            Log.d("" + this.getClass().getName(), "Method: " + method.getName());
            Log.d("" + this.getClass().getName(), "Return Type: " + method.getReturnType());
            Log.d("" + this.getClass().getName(), "Class: " + method.getClass());
            Log.d("" + this.getClass().getName(), "Declaring Class: " + method.getDeclaringClass());

            if(method.getReturnType().getName().contains("int")) {
                try {
                    Method m = method.getDeclaringClass().getMethod(method.getName(), Integer.TYPE);
                    int temp = (int) m.invoke(null, 0); //first argument is the object to invoke on, ignored if static method
                    Log.d("" + this.getClass().getName(),"temp value: " + temp);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            Log.d("" + this.getClass().getName(), "--------------------------");
        }
    }

这是我的日志摘要:

11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: --------------------------
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Method: equals
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Return Type: boolean
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Class: class java.lang.reflect.Method
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Declaring Class: class java.lang.Object
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: --------------------------
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: --------------------------
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Method: getAge
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Return Type: int
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Class: class java.lang.reflect.Method
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: Declaring Class: class productions.widowmaker110.byteme.ExampleObject
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err: java.lang.NoSuchMethodException: getAge [int]
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.Class.getMethod(Class.java:664)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.Class.getMethod(Class.java:643)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at Library.ByteMe.examine(ByteMe.java:94)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at productions.widowmaker110.byteme.MainActivity.onCreate(MainActivity.java:21)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.Activity.performCreate(Activity.java:5958)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.ActivityThread.access$800(ActivityThread.java:144)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.os.Handler.dispatchMessage(Handler.java:102)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.os.Looper.loop(Looper.java:155)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at 安卓.app.ActivityThread.main(ActivityThread.java:5696)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at com.安卓.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at com.安卓.internal.os.ZygoteInit.main(ZygoteInit.java:823)
11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe: --------------------------

我查找了NoSuchMethodFound错误,大多数stackoverflow说这是由于方法是private,但我的方法是public。examine()中的invoke方法应该返回20,因为这是我在main活动中创建的对象的年龄。但它只是抛出了一个例外。帮忙

编辑Alain O'Dea,谢谢你的帮助。这是我必须改变的,才能让它发挥作用

 public void examine(Object obj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        //Get the list of possible methods held in this object.
        Method[] methods = obj.getClass().getMethods();

        // iterate through them
        for (Method method : methods) {
            Log.d("" + this.getClass().getName(), "--------------------------");
            Log.d("" + this.getClass().getName(), "Method: " + method.getName());
            Log.d("" + this.getClass().getName(), "Return Type: " + method.getReturnType());
            Log.d("" + this.getClass().getName(), "Class: " + method.getClass());
            Log.d("" + this.getClass().getName(), "Declaring Class: " + method.getDeclaringClass());

            if(method.getReturnType().getName().contains("int")) {
                try {
                    int temp = (int) method.invoke(obj);
                    Log.d("" + this.getClass().getName(),"temp value: " + temp);
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            Log.d("" + this.getClass().getName(), "--------------------------");
        }
    }

logcat

11-21 20:48:15.459 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: --------------------------
11-21 20:48:15.469 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: Method: getAge
11-21 20:48:15.469 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: Return Type: int
11-21 20:48:15.469 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: Class: class java.lang.reflect.Method
11-21 20:48:15.469 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: Declaring Class: class productions.widowmaker110.byteme.ExampleObject
11-21 20:48:15.469 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: temp value: 20
11-21 20:48:15.469 26949-26949/productions.widowmaker110.byteme D/Library.ByteMe: --------------------------

共 (2) 个答案

  1. # 1 楼答案

    如果查看类的docs,您将看到getMethod(String name, Class...<?> parameterTypes)接受表示方法名(“getAge”在本例中)和参数类型(Integer)的参数。您正在访问的类没有具有该签名(public int getAge(int age))的方法,因此出现了NoSuchMethodException。这不是在骗你

    另外,既然您已经有了要逐步执行的方法,为什么不直接调用m.invoke(obj)(如果它是正确的方法),而不是再次查询类中的方法呢?这可能会把事情弄清楚一点

    最后,正如你的评论所说,当你调用invoke()时,你需要传递你正在调用方法的对象,除非它是静态的(事实并非如此)。所以你需要把它改成m.invoke(obj)

  2. # 2 楼答案

    您有以下代码:

    int temp = (int) m.invoke(null, 0); //first argument is the object to invoke on, ignored if static method
    

    结果得到了这个堆栈跟踪:

    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err: java.lang.NoSuchMethodException: getAge [int]
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.Class.getMethod(Class.java:664)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.Class.getMethod(Class.java:643)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at Library.ByteMe.examine(ByteMe.java:94)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at productions.widowmaker110.byteme.MainActivity.onCreate(MainActivity.java:21)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.Activity.performCreate(Activity.java:5958)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.ActivityThread.access$800(ActivityThread.java:144)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.os.Looper.loop(Looper.java:155)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5696)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
    11-21 20:08:11.704 18121-18121/productions.widowmaker110.byteme D/Library.ByteMe:              
    

    值得注意的是,getAge(int)是一种非静态(实例)方法:

    public int getAge() {
        return Age;
    }
    

    触发该异常的问题源于以下代码:

    Method m = method.getDeclaringClass().getMethod(method.getName(), Integer.TYPE);
    

    这需要一个不存在的方法int methodName(例如int getAge(int))来触发NoSuchMethodException。这是一个多余的步骤,因为您可以只调用方法上的调用

    不过,这并不能单独起作用,因为调用也有问题。因此,必须对对象进行反射调用,而不是null。这也不是全部问题。方法是int getAge()而不是int getAge(int)。它不需要int参数。因此,您还需要从调用中删除0参数

    下面是正确的一行:

    int temp = (int) method.invoke(obj); //first argument is the object to invoke on, ignored if static method
    

    对象方法的文档。调用(对象,对象…)可供参考:

    public Object invoke(Object obj,
                Object... args)
                  throws IllegalAccessException,
                         IllegalArgumentException,
                         InvocationTargetException
    

    Invokes the underlying method represented by this Method object, on the specified object with the specified parameters. Individual parameters are automatically unwrapped to match primitive formal parameters, and both primitive and reference parameters are subject to method invocation conversions as necessary.

    If the underlying method is static, then the specified obj argument is ignored. It may be null.

    If the number of formal parameters required by the underlying method is 0, the supplied args array may be of length 0 or null.

    If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime type of the target object will occur.

    If the underlying method is static, the class that declared the method is initialized if it has not already been initialized.

    If the method completes normally, the value it returns is returned to the caller of invoke; if the value has a primitive type, it is first appropriately wrapped in an object. However, if the value has the type of an array of a primitive type, the elements of the array are not wrapped in objects; in other words, an array of primitive type is returned. If the underlying method return type is void, the invocation returns null.

    Parameters:

    • obj - the object the underlying method is invoked from
    • args - the arguments used for the method call

    Returns:

    • the result of dispatching the method represented by this object on obj with parameters args

    Throws:

    • IllegalAccessException - if this Method object is enforcing Java language access control and the underlying method is inaccessible.
    • IllegalArgumentException - if the method is an instance method and the specified object argument is not an instance of the class or interface declaring the underlying method (or of a subclass or implementor thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion.
    • InvocationTargetException - if the underlying method throws an exception.
    • NullPointerException - if the specified object is null and the method is an instance method. ExceptionInInitializerError - if the initialization provoked by this method fails.

    资料来源:http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object,%20java.lang.Object...)