一.构造方法
1.获取某个类中声明的构造方法实例对象
先创建这样一个Student类,里面含有两个构造方法,一个属性,一个普通方法:
package venus;
public class Student {
public String name;
public Student() {
}
public Student(String name) {
this.name=name;
}
public void doHomeWork() {
System.out.println(name+"正在做作业");
}
}
以下是第一种获取构造方法的方式:
第9行:获取一个Student类对应的class对象。
第10行:调用getConstructor方法获取clazz变量中Student类中的构造方法。Constructor是用来存储构造方法的类
第12行:在getConstructor方法的参数列表中加入Student类中第二个构造方法的参数列表,则得到的就是Student类中的第二个构造方法。
该方法的特点就是只能获取public修饰符修饰的构造方法。
package venus;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
try {
Class clazz=Student.class;
Constructor constructor = clazz.getConstructor();
System.out.println(constructor.getName());
constructor=clazz.getConstructor(String.class);
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
那么如果想获取非public修饰的构造方法,就要使用下面的方式:
package venus;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
try {
Class clazz=Student.class;
Constructor constructor=clazz.getDeclaredConstructor();
System.out.println(constructor.getName());
constructor=clazz.getDeclaredConstructor(String.class);
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
和上一种方式的区别就是这种方式使用的getDeclaredConstructor方法,它的特点就是无视访问修饰权限。
2.获取该构造方法的信息
以下是获取构造方法信息的代码:
第12行,用constructor对象调用getDeclaringClass方法查看该构造方法的类名。
第15,、16行,用来获取构造方法的修饰符,先调用getModifiers方法获取一个int类型的返回值,然后再用Modifier类对象调用toString方法将该值转为String类型,得到的就是我们要查看的修饰符了。
第19行,getName方法用来查看构造方法的方法名。
第21行,getParameterTypes方法用来获取该构造方法的参数列表,但一个构造方法的参数列表可以有多个数据类型不同的参数,,所以返回值为一个Class类型的数组。
第22、23、24行,对getParameterTypes方法得到的Class类型的数组进行遍历,便可得到class类对象的参数列表了。
package venus;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(String.class);
clazz=constructor.getDeclaringClass();
System.out.println(clazz.getName());
int mod=constructor.getModifiers();
String result=Modifier.toString(mod);
System.out.println(result);
System.out.println(constructor.getName());
Class [] str=constructor.getParameterTypes();
for(Class classs:str) {
System.out.println(classs.getName());
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
以下是输出结果:
3.使用该构造方法
对构造方法的使用,无非就是创建该类的对象,以下是使用构造方法的代码:
第12行,用该构造方法调用newinstance创建Student类对象,并返回一个Object类的上转型对象。
第13行,因为object为上转型对象,所以要调用Student类新增的方法时要将该对象下转型。
第14行,下转型后即可调用Student类新增的doHomeWork方法。
package venus;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object object = constructor.newInstance("Tom");
Student stu=(Student)object;
stu.doHomeWork();
}catch (Exception e) {
e.printStackTrace();
}
}
}
我们可以看到在第11行有一个setAccessible方法,该方法的作用就是,如果要调用的目标方法为private访问权限的,这时按常理来说是不可以在其他类中使用的,但是该setAccessible方法如果传入的boolean型参数为true,则可以无视方法的访问权限来调用。
二.普通方法
1.获取某个类中声明的普通方法实例对象
和构造方法一样,获取普通方法的实例对象的方式也是分为public修饰和无视访问权限的
①第一种获取的方式只能获取public修饰的普通方法,但是不仅限于本类中的方法,还可以获取继承自父类的普通方法:
第8行,创建Student类的class类对象
第9行,用Student类的class类对象调用getMethods方法获取类中的方法,但getMethods方法获取的是类中及继承自父类的的全部方法,所以返回值是一个Method类型的数组。
第10行,对数组进行遍历,将方法打印出来。
package venus;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
Method [] methods = clazz.getMethods();
for(Method method:methods) {
System.out.println(method.getName());
}
}
}
输出结果如下:
②第一种方式将类中及继承自父类的所有方法全部打印了出来,但是如果使用getMethod方法,传入目标方法的方法名和参数列表(没有参数列表可以省略第二个参数),便可实现精准查找目标方法:
package venus;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Method method=clazz.getMethod("doHomeWork");
System.out.println(method.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
这时输出结果为精准的doHomeWork:
③第三种方式就是使用getDeclaredMethods方法,可以无视访问权限,但是只能得到在本类中声明的方法,代码如下:
package venus;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Method [] methods=clazz.getDeclaredMethods();
for(Method method:methods) {
System.out.println(method.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
即使是打印全部方法,但是输出结果只有一个doHomeWork方法,说明不能获取继承自父类的方法:
2.获取该普通方法的信息
为了更好的获取方法的信息,先将Student类修改为下面的代码:
package venus;
public class Student {
public String name;
public Student() {
}
public Student(String name) {
this.name=name;
}
public static int doHomeWork(int a,String [] scores) {
System.out.println("正在做作业");
return 1;
}
}
以下是获取普通方法信息的代码:
第13行,打印该普通方法所在的类。
第15行,和构造方法的原理一样,打印方法的修饰符(包括static)。
第17行,得到该方法的返回值。
第20行,打印该方法的方法名。
package venus;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Method method=clazz.getMethod("doHomeWork");
System.out.println(clazz.getDeclaringClass());
System.out.println(Modifier.toString(method.getModifiers()));
clazz=method.getReturnType();
System.out.println(clazz.getName());
System.out.println(method.getName());
Class [] clazzs = method.getParameterTypes();
for(Class zz:clazzs) {
System.out.println(zz.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
该程序运行结果如下:
3.使用该普通方法
使用构造方法调用的是newinstance,使用普通方法调用的是invoke方法,返回值依然是Object类型的上转型对象,该方法的第一个参数是调用该方法的对象,后面的是一个动态参数,传入的是调用目标方法时传入的参数,代码如下:
package venus;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Method method=clazz.getMethod("doHomeWork",Integer.TYPE,String [].class);
method.setAccessible(true);
Object object=method.invoke(new Student(),1,new String[] {} );
} catch (Exception e) {
e.printStackTrace();
}
}
}
要注意的是,无论目标方法是否是静态的,都必须创建对象来调用。
三.属性
1.获取某个类中声明的属性实例对象
属性的获取和普通方法的获取极为相似,只是使用的方法名发生了一些小小的改变,将Method改为了Field。
①第一种获取方式如下,使用范围与普通方法一样,只能获取public修饰的属性,但是可以获取继承自父类的属性。
package venus;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Field field=clazz.getField("name");
System.out.println(field.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
②第二种获取方式如下,可以无视访问权限获取属性,但是不能获取继承自父类的属性。
package venus;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Field field=clazz.getDeclaredField("name");
System.out.println(field.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.获取该属性的信息
第11行,获取Student类中的name属性。
第12行,调用getDeclaringClass方法获取该属性所属的类。
第13行,和上面的用法一样,获取该属性的修饰符。
第14行,调用getType方法获取该属性的数据类型。
第15行,调用getName方法获取该属性的名字。
package venus;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Field field=clazz.getField("name");
System.out.println(field.getDeclaringClass());
System.out.println(Modifier.toString(field.getModifiers()));
System.out.println(field.getType());
System.out.println(field.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果如下:
3.使用该属性
对属性的操作有两种,一是获取值,二是设置值,分别使用的方法时get和set。
第12行,调用set方法为该属性设置值,传入的第一个参数是一个Student类型对象,第二个参数是为该属性设置的值。
第13行,调用get方法获取该属性的值,传入的参数还是一个Student类型对象,返回值是一个Object类型的上转型对象
package venus;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class clazz=Student.class;
try {
Field field=clazz.getField("name");
field.setAccessible(true);
field.set(new Student(),"Jim");
Object obj=field.get(new Student());
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
要注意的是,无论目标属性是否是静态的,都必须创建对象来调用。