Java反射
反射的作用
- 反编译:.class–>.java
- 通过反射机制访问java对象的属性,方法,构造方法等
哪些地方用到了反射
- Jdbc 加载驱动
- Spring IOC的底层
- Hibernate、Mybatis、等各种框架(基本上各种ORM框架都使用到了反射)
为什么已有class文件,却要用反射获得实例对象
- 反射是动态编译,new是静态编译
- 有时我们需要访问别人类中私有的构造方法、成员方法或属性。java反射可以对私有的构造参数实例化,私有构造参数是new不出来的
创建类对象的三种方式
类对象:指定类型为Class的某个类对象
类的对象:通过类new出来的实例,存放在堆空间中
方法1:
//1.通过对象进行获取
Student student = new Student();
Class<? extends Student> studentClass1 = student.getClass();//getClass()属于Object类中的方法
System.out.println(studentClass1);//class com.shujia.day19.Student
方法2:
//2.通过类名.Class的形式获取
Class<Student> studentClass2 = Student.class;
System.out.println(studentClass2);//class com.shujia.day19.Student
方法3:
/3.通过反射的方式获取,Class.forName(),括号中需传入一个类路径
// 类路径可能获取不到对应的类信息,所以可以抛出ClassNotFoundException
Class<?> studentClass3 = Class.forName("com.shujia.day19.Student");
System.out.println(studentClass3);//class com.shujia.day19.Student
通过反射获取构造方法从而获取对象
当有权限访问类的构造方法时
可以通过:
getConstructor:获取第一个构造方法
getConstructors:获取所有有权限的构造方法
getDeclaredConstructors:获取所有构造方法
等方法获取类的构造方法
//通过反射获取构造方法,从而获取对象
Class<Student> studentClass = Student.class;
//getConstructor->获取第一个构造方法
Constructor<Student> constructor = studentClass.getConstructor();
System.out.println(constructor);
//->public com.shujia.day19.Student()
//getConstructors获取所有有权限的构造方法
Constructor<?>[] constructors = studentClass.getConstructors();
System.out.println(Arrays.toString(constructors));
//->[public com.shujia.day19.Student(java.lang.String,int), public com.shujia.day19.Student()]
//getDeclaredConstructors,获取所有构造方法
Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
//->[public com.shujia.day19.Student(java.lang.String,int), private com.shujia.day19.Student(int), private com.shujia.day19.Student(java.lang.String), public com.shujia.day19.Student()]
//newInstance,获取类对象的实例,注意数组中的构造方法的顺序,取一个构造方法要传入对应的参数
Constructor<?> declaredConstructorArr = declaredConstructors[0];
Object o = declaredConstructorArr.newInstance("ww",18);
System.out.println((Student)o);
//->com.shujia.day19.Student@14ae5a5
当类的构造方法被private修饰无法构建其对象时
需要使用setAccessible(true)方法使其能够被使用
//获取没有权限的构造方法(private修饰)的实例
Constructor<?> declaredConstructorByPrivate = declaredConstructors[1];
//利用.setAccessible(true),使private修饰的构造方法可以被创建实例
declaredConstructorByPrivate.setAccessible(true);
Object o1 = declaredConstructorByPrivate.newInstance(20);
System.out.println(o1);
//com.shujia.day19.Student@7f31245a
通过反射获取类中的属性
通过反射的方式也可以获取类中的属性
要想获取属性先获取类对象,通过类对象名.getFiled、getFileds、getDeclareFileds等方式可以获取到属性。当属性被默认修饰符或private修饰符修饰外界无法访问时,需要通过setAccessible(true)的方式使其可以被外界使用,赋值时采用set()的方式传入类的对象和属性值,就可以给对应的属性赋值。
//要想获取类的属性,先获取类对象
Class<?> studentClass = Class.forName("com.shujia.day19.Student");
System.out.println(studentClass);//class com.shujia.day19.Student
//getField()传入属性名 即可获取到对应的属性,指定属性的名称获取属性 ,注意默认类型的属性会获取不到
Field name = studentClass.getField("name");
System.out.println(name);
//->public java.lang.String com.shujia.day19.Student.name
//getFields,获取有权限获取到的属性,返回一个数组
Field[] fields = studentClass.getFields();
System.out.println(Arrays.toString(fields));
//->[public java.lang.String com.shujia.day19.Student.name, public int com.shujia.day19.Student.age]
//getDeclaredFields,获取所有类的属性
Field[] declaredFields = studentClass.getDeclaredFields();
System.out.println(Arrays.toString(declaredFields));
//->[public java.lang.String com.shujia.day19.Student.name, public int com.shuji
//对属性的使用,设置属性的值
//要想设置属性的值需要先获取类的构造方法,通过构造方法获取类的实例
Constructor<?>[] constructors = studentClass.getConstructors();
// System.out.println(Arrays.toString(constructors));
Object studentObj = constructors[1].newInstance();
//通过属性名.set()的方式可以给对应的属性赋值,括号中传入要赋值的对象,和属性的值
name.set(studentObj,"yz");
System.out.println(studentObj);
//->Student{name='yz', age=0, gender='null', identifyID=0}
//当属性的值被private修饰时
Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
// declaredConstructors[3].setAccessible(true);
Object o = declaredConstructors[4].newInstance();
System.out.println(o);
Field gender = studentClass.getDeclaredField("gender");
gender.setAccessible(true);
gender.set(o,"man");
System.out.println(o);
通过反射获取类中的成员方法
要想获取类的成员方法,首先要获得类对象,通过类对象名.getMethod、.getMethods、.getDeclaredMethods等方式获取类中的方法,再通过类对象获取类的对象,使用invoke的方式调用。当方法被private修饰符修饰外界无法访问时,需要通过setAccessible(true)的方式使其可以被外界使用,如果一个类的对象的一些属性在之前的操做中被赋值,在后续使用set时只需要传入对象和剩下未赋值的属性值即可,否则会报错。
Class<?> studentClass = Class.forName("com.shujia.day19.Student");
//getMethod()获取类一个的方法,()中传入方法名和参数列表
Method printInfo = studentClass.getMethod("printInfo", int.class);
System.out.println(printInfo);
//->public void com.shujia.day19.Student.printInfo(int)
//getMethods(),获取所有有权限访问的方法
Method[] methods = studentClass.getMethods();
System.out.println(Arrays.toString(methods));
//.getDeclaredMethods()获取类的所有方法
Method[] declaredMethods = studentClass.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));
//使被private修饰的方法可以被访问
Method skill = studentClass.getDeclaredMethod("skill");
skill.setAccessible(true);
System.out.println(skill);
//-》private void com.shujia.day19.Student.skill()
Field name = studentClass.getField("name");
//获取构造方法
Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
// declaredConstructors[3].setAccessible(true);
Object o = declaredConstructors[4].newInstance();
// Object o = constructors.newInstance();
name.set(o,"yz");
System.out.println(o);
//->Student{name='yz', age=0, gender='null', identifyID=0}
//invoke 方法 需要传入两个参数,一个是对象,一个是参数,若某个参数在之前设置过,则只需要传入一个对象,和剩下的未传入值的参数。
printInfo.invoke(o,4);
skill.invoke(o);