调用方法
约 1029 字大约 3 分钟
2025-07-15
在 Java 反射中,我们可以通过 Class
实例获取类中的方法 (Method
) 信息。Class
类提供了一系列方法来获取 Method
对象:
方法名 | 描述 |
---|---|
getMethod(name, Class...) | 获取某个 public 的 Method ,包括从父类继承的。 |
getDeclaredMethod(name, Class...) | 获取当前类的某个 Method ,不包括父类。 |
getMethods() | 获取所有 public 的 Method ,包括从父类继承的。 |
getDeclaredMethods() | 获取当前类的所有 Method ,不包括父类。 |
下面是一个示例:
// reflection
public class Main {
public static void main(String[] args) throws Exception {
Class stdClass = Student.class;
// 获取 public 方法 getScore,参数为 String:
System.out.println(stdClass.getMethod("getScore", String.class));
// 获取继承的 public 方法 getName,无参数:
System.out.println(stdClass.getMethod("getName"));
// 获取 private 方法 getGrade,参数为 int:
System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
}
}
class Student extends Person {
public int getScore(String type) {
return 99;
}
private int getGrade(int year) {
return 1;
}
}
class Person {
public String getName() {
return "Person";
}
}
上述代码展示了如何使用 Class
对象获取 public
方法 (包括继承的) 和 private
方法。 获取到的 Method
对象包含了方法的各种信息。
一个 Method
对象包含了一个方法的所有信息:
方法名 | 描述 |
---|---|
getName() | 返回方法名称,例如:"getScore" 。 |
getReturnType() | 返回方法返回值类型,也是一个 Class 实例,例如:String.class 。 |
getParameterTypes() | 返回方法的参数类型,是一个 Class 数组,例如:{String.class, int.class} 。 |
getModifiers() | 返回方法的修饰符,它是一个 int ,不同的 bit 表示不同的含义。 可以使用 Modifier 类进行解码。 |
3.1 调用方法
获取到 Method
对象后,就可以使用它来调用相应的方法。 例如,对于 String s = "Hello world"; String r = s.substring(6);
,可以使用反射进行调用:
// reflection
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
// String对象:
String s = "Hello world";
// 获取String substring(int)方法,参数为int:
Method m = String.class.getMethod("substring", int.class);
// 在s对象上调用该方法并获取结果:
String r = (String) m.invoke(s, 6);
// 打印调用结果:
System.out.println(r); // "world"
}
}
Method
对象的 invoke
方法用于执行方法调用,第一个参数是对象实例,后续参数是方法所需的参数。 注意: substring()
方法存在重载,需要根据参数类型来获取对应的方法。
3.2 调用静态方法
调用静态方法时,invoke
方法的第一个参数传入 null
,因为静态方法不依赖于任何实例对象。 例如,调用 Integer.parseInt(String)
方法:
// reflection
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
// 获取Integer.parseInt(String)方法,参数为String:
Method m = Integer.class.getMethod("parseInt", String.class);
// 调用该静态方法并获取结果:
Integer n = (Integer) m.invoke(null, "12345");
// 打印调用结果:
System.out.println(n);
}
}
3.3 调用非 public
方法
对于非 public
方法,虽然可以通过 Class.getDeclaredMethod()
获取 Method
实例,但直接调用会抛出 IllegalAccessException
。 为了能够调用非 public
方法,需要先调用 Method.setAccessible(true)
方法,允许访问。
// reflection
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
Person p = new Person();
Method m = p.getClass().getDeclaredMethod("setName", String.class);
m.setAccessible(true);
m.invoke(p, "Bob");
System.out.println(p.name); // Bob
}
}
class Person {
String name;
private void setName(String name) {
this.name = name;
}
}
需要注意的是,setAccessible(true)
方法的调用可能会失败,这取决于 JVM 运行时的 SecurityManager
策略,某些安全策略可能会阻止对特定包 (如 java
和 javax
开头的包) 中的类调用 setAccessible(true)
,以确保 JVM 核心库的安全。
3.4 多态
在使用反射调用方法时,仍然遵循多态原则。 如果父类和子类都定义了相同的方法,那么通过父类 Class
对象获取的 Method
实例,作用于子类实例时,实际调用的是子类覆写的方法。
// reflection
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
// 获取Person的hello方法:
Method h = Person.class.getMethod("hello");
// 对Student实例调用hello方法:
h.invoke(new Student()); // Student:hello
}
}
class Person {
public void hello() {
System.out.println("Person:hello");
}
}
class Student extends Person {
public void hello() {
System.out.println("Student:hello");
}
}
上述代码展示了多态的特性,即使通过 Person
类的 hello
方法调用,实际执行的是 Student
类中覆写的 hello
方法。 这和直接使用 Person p = new Student(); p.hello();
的效果是一致的。