一、名词解释
1.什么是Java反射机制?
答:运行时动态获得类信息以及动态调取类中的成分的能力
2.反射的步骤(重点):
反射的第一步都是先得到编译后的class对象,然后就可以得到class的全部成分。
二、代码实践
1.获取类的class对象
获取类的class对象有三种方式,这里只写最简单的一种方式
步骤:
Class 自定义 = 类名.class
例子:
被测试的Dog类
package learn; public class Dog { }
测试类
package learn; public class Test { public static void main(String[] args) { //类名.class Class dog = Dog.class;//获取 System.out.println(dog);//打印 } }
运行结果:
class learn.Dog
=======================================================
2.获取类的构造器对象
被测试的类(里面有有参、无参构造器、set和get方法、toSrring方法)
package learn; public class Dog { private String name; private int age; //被测试类里面放有参和无参构造器和set、get方法 public String getName() {//get return name; } public void setName(String name) {//set this.name = name; } public int getAge() {//get return age; } public void setAge(int age) {//set this.age = age; } public Dog() { System.out.println("无参构造器执行"); } //重写toString,快捷键里面有:Alt+Insert 作用:返回打印的值 @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } public Dog(String name, int age) { System.out.println("有参构造器执行"); this.name = name; this.age = age; } }
获取构造器有4种
(1)只能获取public修饰的(略)
(2)全部都可以获取(学习这个)
测试类
package learn; import java.lang.reflect.Constructor; public class Test { public static void main(String[] args) throws NoSuchMethodException { //1.获取类对象 Class dog = Dog.class; //2.提取类对象中的全部构造器对象 Constructor[] a = dog.getDeclaredConstructors(); //3.用for循环遍历全部的构造器对象 for (Constructor constructor : a) { //打印构造器里面的参数个数。0个代表构造器参数为0,是无参构造器 2个代表构造器有两个参数,是有参构造器 System.out.println(constructor.getName()+"=====>"+constructor.getParameterCount());//learn.Dog=====>0 learn.Dog=====>2 } } }
运行结果:
learn.Dog=====>0
learn.Dog=====>2
(3)只能获取某个单一的public修饰的构造器(略)
(4)可以获取某个单一的构造器
测试类
package learn; import java.lang.reflect.Constructor; public class Test { public static void main(String[] args) throws Exception { //1,获取类对象 Class dog = Dog.class; //获取单个无参构造器对象个数 Constructor cons = dog.getDeclaredConstructor(); System.out.println(cons.getName()+"===>"+cons.getParameterCount()); //如果遇到了私有的构造器,进行暴力破解打开权限 cons.setAccessible(true); //最后获取无参构造器对象 Dog a = (Dog)cons.newInstance(); System.out.println(a); System.out.println("================分割线=========================="); //获取单个有参构造器对象 Constructor cons1= dog.getDeclaredConstructor(String.class,int.class);//被获取的成员变量是什么数据类型,这里就填什么数据类型 System.out.println(cons1.getName()+"===>"+cons1.getParameterCount());//参数一是:获取Dog类名称,参数二:获取参数的个数 //最后获得有构造参数 Dog a1 = (Dog)cons1.newInstance("大哥",18);//传入赋值参数 System.out.println(a1); } }
运行结果:
learn.Dog===>0
无参构造器执行
Dog{name='null', age=0}
================分割线==========================
learn.Dog===>2
有参构造器执行
Dog{name='大哥', age=18}
=====================================================
3.获取类的成员变量
步骤:
1.获取class对象
2.获取Field对象
3.赋值或者获取值
(1)获取全部成员变量
被测试的类
package learn; public class Dog { private String name; private int age; //被测试类里面放有参和无参构造器和set、get方法 public String getName() {//get return name; } public void setName(String name) {//set this.name = name; } public int getAge() {//get return age; } public void setAge(int age) {//set this.age = age; } public Dog() { System.out.println("无参构造器执行"); } //重写toString,快捷键里面有:Alt+Insert 作用:返回打印的值 @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } public Dog(String name, int age) { System.out.println("有参构造器执行"); this.name = name; this.age = age; } }
测试类
package learn; import java.lang.reflect.Field; public class Test extends PeopleTest{ public static void main(String[] args) { //1.获取class对象 Class dog = Dog.class; //2.获取全部成员变量 Field[] fields = dog.getDeclaredFields(); //3.用for循环遍历出来 for (Field field : fields) { //4.参数一:获取具体成员变量 参数二:获取成员类型 System.out.println(field.getName()+"====>"+field.getType()); } } }
运行结果:
name====>class java.lang.String
age====>int
(2)获取某个成员变量
被测试的类(上一个测试类)
测试类
package learn; import java.lang.reflect.Field; public class Test extends PeopleTest{ public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { //一、获取某个成员变量 //1.获取class对象 Class dog = Dog.class; //2.获取某个成员变量---age Field field = dog.getDeclaredField("age");//遇到异常抛出就好 //3.暴力打开权限 field.setAccessible(true); //赋值 Dog d = new Dog();//new要赋值的类 field.set(d,18);//把获取到的成员变量放到新new出来的里面 赋值18 System.out.println(d); //取值 Object o = field.get(d); System.out.println(o); } }
运行结果:
无参构造器执行
Dog{name='null', age=18}
18
=====================================================
4.获取类的方法
步骤:
1.获取类的对象
2. 用getDeclaredMethods获取全部方法或者getDeclaredMethod获取某个方法
3.用for循环遍历出来
遍历.getName()-----获取方法名字
遍历.getReturnType()--获取方法返回值的类型
遍历.getParameterCount()--获取方法个数
如果获取某个就不用遍历和需要暴力破解,在第二步时候不一样,其他的基本一样
(1)获取全部方法
被测试的类
package learn; public class Dog { //自定义的成员变量 private String name; public int age; //生成的有参构造 public Dog(String name) { this.name = name; } //狗跑的方法 public void run(){ System.out.println("狗在跑"); } //狗在吃东西的方法 public String eat(){ System.out.println("我会吃"); return "吃的很开心"; } //生成的set和get方法 public String getName() { return name; } public void setName(String name) { this.name = name; } }
测试类
package learn; import java.lang.reflect.Method; public class Test extends PeopleTest{ public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { //1.获取类的对象 Class c = Dog.class; //2.获取全部方法(包括私有)---用getDeclaredMethods方法获取 Method[] methods = c.getDeclaredMethods(); //遍历全部方法 for (Method method : methods) { System.out.println(method.getName()+"这是方法的名字"+method.getReturnType()+"这是返回值类型"+method.getParameterCount()+"参数个数"); } } }
运行结果:
getName这是方法的名字class java.lang.String这是返回值类型0参数个数
run这是方法的名字void这是返回值类型0参数个数
setName这是方法的名字void这是返回值类型1参数个数
eat这是方法的名字class java.lang.String这是返回值类型0参数个数
(1)获取某个方法
被测试的类(上一个测试类)
测试类
package learn; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test extends PeopleTest{ public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { //1.获取类的对象 Class c = Dog.class; //2.获取某个方法 Method m = c.getDeclaredMethod("run");//获取run方法,遇到异常直接抛出 //暴力打开权限 m.setAccessible(true); //3.触发方法的执行 Dog d = new Dog(); //注意:如果没有方法返回来的,那么就会返回null Object invoke = m.invoke(d); System.out.println(invoke); } }
运行结果:
狗在跑
null
旁白:反射就是先通过获取类的对象,然后再根据需要看获取构造方法、成员变量或者方法,根据需要获取,一般全部获得用得都是数组方式,用到的方法里面会含有一个s。而用到暴力打开私有权限的最多的就是获取单一某个成员变量时候了。反射还有一个擦除泛型的,就是破坏泛型原则的,目前这篇文章里面主要讲的就是破坏封装性的。