一、什么是反射
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取字节码文件对象的三种方式;:
1、Class clazz1 = Class.forName(“全限定类名”);
// 通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
2、Class clazz2 = Person.class;
// 当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
3、Class clazz3 = p.getClass();
// 通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
二、反射的使用
新建User类
使用user类进行测试
public class User {
private int id;
private int age;
private String name;
//javabean必须要有无参的构造方法!
public User() {
}
public User(int id, int age, String name) {
super();
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setUname() {
this.name = "cczhang";
}
}
通过反射获取构造方法并使用
String path = "com.cczhang.reflection.bean.User";
try {
Class<User> clazz = (Class<User>) Class.forName(path);
//获得构造器信息
Constructor[] constructors = clazz.getDeclaredConstructors();
Constructor c1 = clazz.getDeclaredConstructor(int.class,int.class,String.class);
System.out.println("获得构造器:"+c1);
Constructor c2 = clazz.getDeclaredConstructor();
System.out.println("获得构造器:"+c2);
for(Constructor temp:constructors){
System.out.println("构造器:"+temp);
}
//通过反射API调用构造方法,构造对象
User u = clazz.newInstance(); //其实是调用了User的无参构造方法
System.out.println(u);
Constructor<User> c = clazz.getDeclaredConstructor(int.class,int.class,String.class);
User u2 = c.newInstance(1001,18,"cczhang");
System.out.println(u2.getName());
System.out.println(u2.getAge());
} catch (Exception e) {
}
1.获取构造方法:
1).批量.获取构造方法的方法:
public Constructor[] getConstructors():所有"公有的"构造方法。
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)。
2).获取单个的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法。
public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有。
2、调用构造方法:
1)Constructor–>newInstance(Object… initargs)。
2)newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:
newInstance(Object… initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用。
获取成员变量并调用
//获取属性信息
// Field[] fields = clazz.getFields(); //只能获得public的field
Field[] fields = clazz.getDeclaredFields();//获得所有的field
System.out.println(fields.length);
for(Field temp:fields){
System.out.println("属性:"+temp);
}
//通过反射API操作属性
User user = clazz.newInstance();
Field f = clazz.getDeclaredField("name");
f.setAccessible(true); //这个属性不需要做安全检查了,可以直接访问
f.set(user, "cczhang"); //通过反射直接写属性
System.out.println(user.getName()); //通过反射直接读属性的值
System.out.println(f.get(user));
注: f.set(user, “cczhang”);为User对象中的name属性赋值,即user.name = “cczhang”。第一个参数:要传入设置的对象,第二个参数:要传入实参。
暴力访问method.setAccessible(true);
获取成员方法并调用
//获取方法信息
Method[] methods = clazz.getDeclaredMethods();
for(Method m:methods){
System.out.println("方法:"+m);
}
Method m01 = clazz.getDeclaredMethod("getName", null);
//如果方法有参,则必须传递参数类型对应的class对象
Method m02 = clazz.getDeclaredMethod("setName", String.class);
//通过反射API调用普通方法
User u3 = clazz.newInstance();
Method method = clazz.getDeclaredMethod("setName", String.class);
//需要两个参数,一个是要调用的对象(获取的反射),一个是实参
method.invoke(u3, "cczhang");
System.out.println(u3.getName());
通过反射获取泛型信息
public class Demo04 {
public void test01(Map<String,User> map, List<User> list){
System.out.println("Demo04.test01()");
}
public Map<Integer,User> test02(){
System.out.println("Demo04.test02()");
return null;
}
public static void main(String[] args) {
try {
//获得指定方法参数泛型信息
Method m = Demo04.class.getMethod("test01", Map.class,List.class);
Type[] t = m.getGenericParameterTypes();
for (Type paramType : t) {
System.out.println("#"+paramType);
if(paramType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("泛型类型:"+genericType);
}
}
}
//获得指定方法返回值泛型信息
Method m2 = Demo04.class.getMethod("test02", null);
Type returnType = m2.getGenericReturnType();
if(returnType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("返回值,泛型类型:"+genericType);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
更多反射的用法请查阅JAVA的API文档。
相关连接
https://blog.csdn.net/wjzj000/article/details/54179894
https://blog.csdn.net/sinat_38259539/article/details/71799078