我正在编写API,但我遇到了使用反射的问题。我想要做的是从自定义对象类调用一个方法,并将值返回到被调用的点。调用的开始发生在MainActivity.java
中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.java的文件中进行此调用时:
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(), "--------------------------");
}
}
这是我的logcat的摘录:
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 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: --------------------------
我查找了NoSuchMethodFound错误,大多数stackoverflow表示这是由于方法为private
但我的方法是public
。 examine()中的invoke方法应该返回20,因为那是我在MainActivity中创建的对象的年龄。它只是抛出异常。帮助
编辑 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: --------------------------
答案 0 :(得分:3)
您有以下代码:
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
Object Method.invoke(Object,Object ...)的文档可供参考:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
在on上调用此Method对象表示的基础方法 具有指定参数的指定对象。个人 参数自动解包以匹配原始形式 参数,以及原始参数和参考参数都受制于 必要时进行方法调用转换。
如果底层方法是静态的,那么指定的obj参数是 忽略。它可能为空。
如果底层方法所需的形式参数的数量 如果为0,则提供的args数组的长度可以为0或null。
如果底层方法是实例方法,则使用它调用它 Java语言中记录的动态方法查找 规范,第二版,第15.12.4.4节;特别是, 将发生基于目标对象的运行时类型的覆盖。
如果底层方法是静态的,则声明该方法的类 如果尚未初始化,则进行初始化。
如果方法正常完成,则返回它返回的值 调用的调用者;如果值具有基本类型,则它是第一个 适当地包裹在一个物体中。但是,如果值具有类型 对于基本类型的数组,数组的元素不是 包裹在物体中;换句话说,一个原始类型的数组是 回。如果底层方法返回类型为void,则调用 返回null。
参数:
- obj - 从
调用基础方法的对象- args - 用于方法调用的参数
返回:
- 调度由此表示的方法的结果 obj上的对象参数args
抛出:
- IllegalAccessException - 如果此Method对象正在执行 Java语言访问控制和底层方法是 不可访问。
- IllegalArgumentException - 如果方法是 instance方法和指定的object参数不是实例 类或接口声明底层方法(或一个 子类或其实现者);如果实际和正式的数量 参数不同;如果是原始参数的解包转换 失败;或者,如果在可能的展开后,参数值不能 通过方法转换为相应的形式参数类型 调用转换。
- InvocationTargetException - 如果是 底层方法抛出异常。
- NullPointerException - 如果 指定的对象为null,方法是实例方法。 ExceptionInInitializerError - 如果由此引发的初始化 方法失败。
答案 1 :(得分:2)
如果查看Class类的docs,您会看到getMethod(String name, Class...<?> parameterTypes)
接受表示方法名称的参数(在您的情况下为“getAge”)和参数类型(Integer) 。您正在访问的类没有带该签名的方法(public int getAge(int age)
),因此NoSuchMethodException。这不是骗你的。
此外,由于您已经有了逐步执行的方法,为什么不调用m.invoke(obj)
如果它是正确的,而不是再次查询该方法的类?这可能会让事情变得清醒一些。
最后,正如你的评论所说,当你调用invoke()
时,你需要传递你正在调用该方法的对象,除非它是静态的(它不是)。因此,您需要将其更改为m.invoke(obj)
。