一、获取和调用普通方法
Class
类提供了以下几个方法来获取Method
:
- Method getMethod(name, Class...):获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
- Method[] getMethods():获取所有public的Method(包括父类)
- Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
下面给出两个简单的示例:
public static <T> void getDeclaredMethods(T t) {
Object obj = (Object) t;
Class cls = obj.getClass();
Method[] methods = cls.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i]);
}
}
public static <T> void getMethod(T t) throws NoSuchMethodException {
Object obj = (Object) t;
Class cls = obj.getClass();
System.out.println(cls.getMethod("setName", String.class));
System.out.println(cls.getMethod("getName"));
}
像Field
对象包含了一个字段的所有信息一样,Method
对象也包含一个方法的所有信息,下面简单介绍几个常用的方法:
-
getName()
:返回方法名称; -
getReturnType()
:返回方法返回值类型,也是一个Class
实例; -
getParameterTypes()
:返回方法的参数类型,是一个Class
数组,例如:{String.class, int.class}
;
示例:
public static <T> void getMethodReturnType(T t) throws NoSuchMethodException {
Object obj = (Object) t;
Class cls = obj.getClass();
Method method = cls.getMethod("setName", String.class);
System.out.println(method.getName()); // setName
System.out.println(method.getReturnType()); // void
Class<?>[] p = method.getParameterTypes();
for (int i = 0; i < p.length; i++) {
System.out.println(p[i]); // class java.lang.String
}
}
下面给出一个具体的调用substring
方法的示例:
public static void getSubstringMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String str = "Happy-new-year";
// 获取String substring(int, int)方法:
Method m = String.class.getMethod("substring", int.class, int.class);
// 在s对象上调用该方法并获取结果:
String r = (String) m.invoke(str, 2, 5);
// 打印调用结果:
System.out.println(r);
}
调用Method
实例的invoke
方法就相当于调用该方法。invoke的第一个参数是要调用的对象实例(此处substring
是要对str
使用,所以传入str
),后续为可变参数,要与调用方法的参数保持一致。
有一些特殊的方法,情况稍有不同。
- 假如调用的方法为
static
方法,因为不需要指定调用的实例对象,所以invoke
的第一个参数需设置为null
。 - 假如调用的方法为
private
或者protect
方法。需要采取和访问私有Field
的一样的方法:在使用invoke
方法之前,需设置Method.setAccessible(true)
。 - 假如某一方法在父类中存在,同时在子类中也进行了重写,即存在多态的情况。使用
invoke
调用同样支持多态原则,会根据传入invoke
方法的第一个参数的实际类型来进行调用。
二、获取和调用构造方法
构造方法其实也属于特殊方法的一种,但是因为其较普通方法更为特殊,因此特意单独出来。
在JAVA-通过反射获取任意类的字段 中,介绍过:
- 如果获取到了一个
Class
实例,通过该Class
实例的newInstance
方法来创建对应类型的实例,但是这种方法有局限。 - 局限是:只能调用public的无参数构造方法。带参数的构造方法或者非public的构造方法都无法通过Class.newInstance()调用。
如果想要调用任意的构造器方法,可以使用反射提供的Constructor
对象。Constructor
对象类似于Method
方法,包含一个构造方法的所有信息,不同点在于调用结果总是返回实例。
Class
类提供了以下几个方法来获取Constructor
:
-
getConstructor(Class...)
:获取一个public
的Constructor
, -
getDeclaredConstructor(Class...)
:获取一个Constructor
, -
getConstructors()
:获取所有public
的Constructor
, -
getDeclaredConstructors()
:获取所有Constructor
。
同样的,调用非public
的Constructor
时,必须首先通过setAccessible(true)
设置允许访问。
示例:
- 首先使用
Constructor
对象查看User有哪些构造器(包括私有构造器):
public static void queryUserConstructor(@NotNull Class<?> classType) {
Constructor<?>[] constructors = (Constructor<?>[]) classType.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
输出显示,共有三种构造器,其中一种是私有构造器:
private simplespring_anno.entity.User(java.lang.String,boolean)
public simplespring_anno.entity.User(java.lang.String)
public simplespring_anno.entity.User()
- 然后使用
Constructor
对象调用User的构造器
public static <T> void testUserConstructor(@NotNull Class<T> classType, String name, boolean flag) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//无参公有构造器User()
Constructor<?> constructor = classType.getConstructor();
User user1 = (User) constructor.newInstance();
System.out.println(user1);
System.out.println("--------------------------------------");
//带参(String)构造器User(java.lang.String)
Constructor<?> stringConstructor = classType.getConstructor(String.class);
User user2 = (User) stringConstructor.newInstance(name);
System.out.println(user2);
System.out.println("--------------------------------------");
//带参(String, boolean)构造器User(java.lang.String,boolean)
Constructor<?> strBoolConstructor = classType.getDeclaredConstructor(String.class, boolean.class);
strBoolConstructor.setAccessible(true);
User user3 = (User) strBoolConstructor.newInstance(name, flag);
System.out.println(user3);
}
输出:
无参构造器:User()
用户名:李四
--------------------------------------
公有构造器:User(java.lang.String)
用户名:张三
--------------------------------------
私有构造器:User(java.lang.String,boolean)
用户名:张三
时来天地皆同力,运去英雄不自由。