一.反射是什么?
1.1 涵义
反射是指在运行时动态地获取一个类的信息,包括类的成员变量、构造方法和方法等。通过反射机制,可以在程序运行期间动态地加载并使用任意一个类,并在程序运行期间动态地获取或修改它的字段(属性)和方法等信息,甚至可以在运行时生成一个新的对象、调用它的方法以及操作它的属性
1.2 反射的操作有哪些
- 获取类的类型信息;
- 获取类的属性信息;
- 获取类的构造方法信息;
- 获取类的方法信息;
- 动态创建对象;
- 调用对象的方法和操作对象的属性。
二.反射的作用
2.1 优点
1.实现程序的动态性和灵活性,有助于程序的扩展和维护;
2.可以根据不同的需求灵活地获取和操作类的方法和属性;
3.通过动态代理实现AOP编程;
4.可以在框架的开发中使用反射机制实现依赖注入任意类型的对象。
2.2 缺点
1.反射机制的执行效率比较低,比直接调用方法速度慢;
2.由于反射可以绕过Java的封装机制,容易导致安全问题,需要谨慎使用;
3.使用反射机制可能会使代码变得复杂和难以理解,对代码的可维护性有一定影响。
三.类类
获取类类有三种方式(以Student.java为例)
package com.yinzi.reflect; public class Student { private String sid; private String sname; public Integer age; static{ System.out.println("加载进jvm中!"); } public Student() { super(); System.out.println("调用无参构造方法创建了一个学生对象"); } public Student(String sid) { super(); this.sid = sid; System.out.println("调用带一个参数的构造方法创建了一个学生对象"); } public Student(String sid, String sname) { super(); this.sid = sid; this.sname = sname; System.out.println("调用带二个参数的构造方法创建了一个学生对象"); } @SuppressWarnings("unused") private Student(Integer age) { System.out.println("调用Student类私有的构造方法创建一个学生对象"); this.age = age; } public String getSid() { return sid; } public void setSid(String sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public void hello() { System.out.println("你好!我是" + this.sname); } public void hello(String name) { System.out.println(name + "你好!我是" + this.sname); } @SuppressWarnings("unused") private Integer add(Integer a, Integer b) { return new Integer(a.intValue() + b.intValue()); } }
注意: 一切获取反射的操作都从获取类类/类对象开始
Class.forName()----这是通过内存地址的方式获取 这个一般用于连接数据库的情况
类名.class 这个用于增删改
对象.getclass() 这个用于查询
四.反射实例化
主要是调用两个方法:
getConstructor------>调用公共的方法
getDeclaredConstructor ------>调用私有的方法
注意:在调用私有方法要先打开访问权限,调用setAccessible(true);方法
//一切反射从获取类开始 Class c1 = Class.forName("com.yinzi.reflect.Student"); //1.调用无参构造方法 Student s = (Student) c1.newInstance(); /// System.out.println(s); //2.调用一个参数的构造方法 //parameterTypes:其参数的类别 类别.class Constructor c=c1.getConstructor(String.class); // initargs:属性的值 Student s2 = (Student) c.newInstance("haha"); System.out.println(s2); //3.调用俩个参数的方法 //parameterTypes:其参数的类别 类别.class Constructor c2=c1.getConstructor(String.class,String.class); // initargs:属性的值 Student s3 = (Student) c2.newInstance("haha","heiei"); System.out.println(s3); //4.调用带私有化的构造方法getDeclaredConstructor Constructor c3=c1.getDeclaredConstructor(Integer.class); // 打开访问权限 c3.setAccessible(true); // initargs:属性的值 Student s4 = (Student) c3.newInstance(12); System.out.println(s4);
输出结果:
注意:一个实体类如果添加了有参构造方法就要添加一个无参构造方法
如果在实体类中没有无参构造方法,就会包以下错误
五.反射动态方法的调用
和上面是差不多的!
主要是调用两个方法:
getMethod------>调用公共的方法
getDeclaredMethod ------>调用私有的方法
package com.yinzi.reflect; import java.lang.reflect.Method; /** * 动态方法的调用 * @author 86131 * */ public class demo3 { public static void main(String[] args) throws Exception { Class c = Student.class; Student stu = (Student) c.newInstance(); //1.调用无参构造方法 Method m1=c.getMethod("hello");//里面放方法名字和要传的参数类型如果没有就不需要传 Object invoke = m1.invoke(stu);//里面放类,和参数值 System.out.println(invoke); //2.调用1个参构造方法 Method m2=c.getMethod("hello",String.class);//里面放方法名字和要传的参数类型如果没有就不需要传 Object invoke2 = m2.invoke(stu,"haha");//里面放类,和参数值 System.out.println(invoke2); //3.调用私有,1个参构造方法 Method m3=c.getDeclaredMethod("add",Integer.class,Integer.class); //打开访问权限 m3.setAccessible(true); Object invoke3 = m3.invoke(stu, 12,12); System.out.println(invoke3); } }
六.反射读写属性
主要是调用两个方法:
getDeclaredField
getDeclaredFields
输出结果:
第二种方式,根据属性获取值
输出结果: