Java 使用反射来调用公共方法
我正在编写一个API,在使用反射时遇到了一个问题。我要做的是从自定义对象类调用一个方法,并将值返回到调用的点。调用的开始发生在MainActivity.java中Java 使用反射来调用公共方法,java,android,reflection,Java,Android,Reflection,我正在编写一个API,在使用反射时遇到了一个问题。我要做的是从自定义对象类调用一个方法,并将值返回到调用的点。调用的开始发生在MainActivity.java中 public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState)
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(), "--------------------------");
}
}
这是我的日志摘录:
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中创建的对象的年龄。但它只是抛出了一个异常。帮忙
编辑阿兰·奥黛,谢谢你的帮助。这是我必须改变的,以使其发挥作用
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: --------------------------
您有以下代码:
int temp = (int) m.invoke(null, 0); //first argument is the object to invoke on, ignored if static method
Method m = method.getDeclaringClass().getMethod(method.getName(), Integer.TYPE);
结果是,您得到了这个堆栈跟踪:
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)是一种非静态(实例)方法:
触发该异常的问题源于以下代码:
int temp = (int) m.invoke(null, 0); //first argument is the object to invoke on, ignored if static method
Method m = method.getDeclaringClass().getMethod(method.getName(), Integer.TYPE);
这将要求使用一个不存在的方法intmethodname(例如intgetage(int)),触发NoSuchMethodException。这是一个多余的步骤,因为您可以只调用方法上的调用
但是,由于调用也有问题,所以这一点无法单独工作。因此,您必须对对象进行反射调用,而不是null。这也不是全部问题。方法是intgetage()而不是intgetage(int)。它不接受int参数。因此,您还需要从调用中删除0参数
以下是更正的行:
int temp = (int) method.invoke(obj); //first argument is the object to invoke on, ignored if static method
对象方法.invoke(对象,对象…)的文档可供参考:
在上调用此方法对象表示的基础方法
具有指定参数的指定对象。个人
参数将自动展开以匹配基元形式
参数,并且基本参数和参考参数都受
根据需要进行方法调用转换
如果基础方法是静态的,则指定的obj参数为
忽略。它可能是空的
如果基础方法所需的形式参数的数量
如果为0,则提供的args数组的长度可能为0或null
如果基础方法是实例方法,则使用
Java语言中记录的动态方法查找
规范,第二版,第15.12.4.4节;特别地,
将根据目标对象的运行时类型进行重写
如果基础方法是静态的,则声明该方法的类
如果尚未初始化,则初始化
如果方法正常完成,则返回它返回的值
调用方;如果该值具有基元类型,则为第一个
适当地包装在一个对象中。但是,如果值的类型为
对于基元类型的数组,数组的元素不是
包裹在物体中;换句话说,基本类型的数组是
返回。如果基础方法返回类型为void,则调用
返回null
参数:
- obj—从中调用基础方法的对象
- args-用于方法调用的参数
- 调度由以下表达式表示的方法的结果 对象上具有参数args的对象
- IllegalAccessException-如果此方法对象正在强制 Java语言访问控制,底层方法是 难以接近
- IllegalArgumentException-如果方法是 实例方法,指定的对象参数不是实例 声明基础方法的类或接口(或 子类或其实施者);如果实际和正式的 参数不同;如果为基元参数执行展开转换 失败;或者,如果在可能的展开之后,无法创建参数值 通过方法转换为相应的形式参数类型 调用转换
- InvocationTargetException-如果 底层方法引发异常
- NullPointerException-如果 指定的对象为null,该方法为实例方法。 ExceptionInInitializerError-如果此操作引发初始化 方法失败
来源:如果您查看类的属性,您将看到
getMethod(字符串名称,类…参数类型)
接受表示方法名称(“getAge”在您的示例中)和参数类型(整数)的参数。您正在访问的类没有具有该签名的方法(public int-getAge(int-age)
),因此出现NoSuchMethodException。这不是在骗你
另外,既然您已经有了要逐步执行的方法,为什么不直接调用m.invoke(obj)
(如果它是正确的),而不是再次查询类中的方法呢?那可能会把事情弄清楚一点
最后,正如您的评论所说,当您调用
invoke()
时,您需要传递正在调用方法的对象,除非它是静态的(实际上不是)。因此,您需要将其更改为m.invoke(obj)
@SotiriosDelimanolis从行Method m=Method.getDeclaringClass().getMethod(Method.getName(),Integer.TYPE)中的对象类获取值;int temp=(int)m.invoke(null,0)//第一个参数是要调用的对象,如果静态方法Log.d(“+this.getClass().getName(),”temp value:“+temp”),则忽略该参数我不知道你想说什么