目录
getDeclaredConstructor() 获取私有的构造方法
一.反射机制讲解
1.反射机制的概念
反射是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法
并且对于任意一个对象,都能够调用它的任意一个方法
这种动态获取信息以及动态调用对象方法的功能称为反射机制。
简单来说
动态获取类中的信息,就是反射机制。
ps:反射机制是框架设计的灵魂
2.反射机制的优缺点
优点
- 反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
- 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类
- 使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
- 反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
缺点
- 使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。
- 使用反射性能较低,需要解析字节码(.class文件),将内存中的对象进行解析(避免在对性能要求很高的程序或经常被执行的代码中使用反射)
二.反射的使用
1.获取Class的三种方法
用一个学生类(Student)来做示范
Class.forName(完整类名)
这个我们在连接数据库驱动时使用过,下面大家看下示例代码:
//通过该类的完整名字获取Class对象 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
类名.class
直接通过类名.class获得Class对象,代码如下:
//通过类名.class获取到Class对象 Class<Student> clazz02=(Class<Student>)Student.class;
对象.getClass
这种情况一般都是当构造函数没有被私有化,可以直接将该类实例得到对象,进行操作,如果类被私有化构造函数,那么还是使用上面两种。代码如下:
//通过对象.getClass获取Class对象 Student stu=new Student(); Class<Student> clazz03=(Class<Student>)stu.getClass();
注:运行期间,一个类只产生一个Class对象产生,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
大家可以将这三个代码同时运用,然后打印,都是一样的
2.通过反射实例化
我们通过反射获取到构造函数,将该类实例化。
学生类代码如下:
package com.yjx.test; public class Student { private Integer id; private String name; private Integer age; //get和set方法 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } /** * 无参构造 */ public Student() { System.out.println("调用无参构造方法创建了一个学生对象"); } private Student(Integer id, String name) { super(); this.id = id; this.name = name; } public Student(Integer id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public void hello() { System.out.println("你好!我是" + this.name); } public void hello(String name) { System.out.println(name + "你好!我是" + this.name); } @SuppressWarnings("unused") private Integer add(Integer a, Integer b) { return new Integer(a.intValue() + b.intValue()); } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
getConstructor() 获取公开构造方法
获取公开的构造方法我们就是使用到该方法,如果需要调用无参构造,我们就里面什么都不填,如果是其他的构造方法,那么那个构造方法中参数有几个以及什么属性,都要在该方法中依次输入。
package com.yjx.test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test01 { public static void main(String[] args) throws Exception { //通过该类的权限命名获取Class对象 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student"); //通过类名.class获取到Class对象 Class<Student> clazz02=(Class<Student>)Student.class; //通过对象.getClass获取Class对象 Student stu=new Student(); Class<Student> clazz03=(Class<Student>)stu.getClass(); //通反射实例化,class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法 //无参构造就不传值进去 Constructor<Student> c01=clazz01.getConstructor(); //获取到Student对象 Student stu01=c01.newInstance(); stu01.setName("hhh"); stu01.setId(1); stu01.setAge(18); System.out.println(stu01); //通过反射实例,通过class对象获取到该构造方法 //传入该构造方法相对应的值 Constructor<Student> c02=clazz01.getConstructor(Integer.class,String.class,Integer.class); //得到Student对象,newInstance()方法可以根传入的参数,调用该构造函数。 Student stu02=c02.newInstance(2,"小黄",18); System.out.println(stu02); } }
getDeclaredConstructor() 获取私有的构造方法
setAccessible() 是否启动和禁用安全检查
1.setAccessible()方法的作用是启动和禁用访问安全检查的开关。
2.setAccessible()方法默认是false,那么反射的对象需要进行安全检查,那么是无法调用该函数的。
3.将setAccessible()方法里的值为true,那么反射的对象不需要进行安全检查,因为禁用了安全检查。
代码如下:
package com.yjx.test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test01 { public static void main(String[] args) throws Exception { //通过该类的权限命名获取Class对象 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student"); //通过类名.class获取到Class对象 Class<Student> clazz02=(Class<Student>)Student.class; //通过对象.getClass获取Class对象 Student stu=new Student(); Class<Student> clazz03=(Class<Student>)stu.getClass(); //获取到私有的构造方法 Constructor<Student> c03=clazz01.getDeclaredConstructor(Integer.class,String.class); //在我们访问私有的构造方法或者其他私有的方法时,就需要使用setAccessible()方法 //setAccessible作用是启动和禁用访问安全检查的开关 //当里面的值为true时则反射的对象在使用时,抑制Java语言访问检查 //默认是为false,那么反射的对象进行Java语言访问检查 c03.setAccessible(true); //实例Student Student stu03=c03.newInstance(3,"小黑"); System.out.println(stu03); } }
三.反射动态方法调用
getMethod() 调用公开的方法
1.getMethod()方法是调用类中的公开方法,往该getMethod()方法中传入方法的名字和该方法所需要传入的那种类型参数。
2.例如无参的方法getMethod("hello")
3.如果需要调用一个有参的方法,该方法需要传入一个String类型的参数,那么getMethod("hello",String.class)
invoke()
调用Method类代表的方法,可以实现动态调用
代码如下:
package com.yjx.test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test01 { public static void main(String[] args) throws Exception { //通过该类的权限命名获取Class对象 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student"); //通过类名.class获取到Class对象 Class<Student> clazz02=(Class<Student>)Student.class; //通过对象.getClass获取Class对象 Student stu=new Student(); Class<Student> clazz03=(Class<Student>)stu.getClass(); //通反射实例化,通过class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法 //无参构造就不传值进去 Constructor<Student> c01=clazz01.getConstructor(); //获取到Student对象 Student stu01=c01.newInstance(); stu01.setName("hhh"); stu01.setId(1); stu01.setAge(18); System.out.println(stu01); //反射动态方法调用 //将方法的名字传进去 Method m01=clazz01.getMethod("hello"); m01.invoke(stu01); //将方法的名字,以及该方法所需要传的参数一一对应放入。 Method m02=clazz01.getMethod("hello",String.class); //invoke()方法的作用:调用Method类代表的方法,可以实现动态调用 //这串代码就是stu01.hello("小白") m02.invoke(stu01,"小白"); } }
getDeclaredMethod() 调用私有的方法
package com.yjx.test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test01 { public static void main(String[] args) throws Exception { //通过该类的权限命名获取Class对象 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student"); //通过类名.class获取到Class对象 Class<Student> clazz02=(Class<Student>)Student.class; //通过对象.getClass获取Class对象 Student stu=new Student(); Class<Student> clazz03=(Class<Student>)stu.getClass(); //通反射实例化,通过class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法 //无参构造就不传值进去 Constructor<Student> c01=clazz01.getConstructor(); //获取到Student对象 Student stu01=c01.newInstance(); stu01.setName("hhh"); stu01.setId(1); stu01.setAge(18); System.out.println(stu01); //调用私有的方法 Method m03=clazz01.getDeclaredMethod("add",Integer.class,Integer.class); m03.setAccessible(true); //因为原本得到的是一个object,而该方法中返回的值为int类型,所以需要进行一个强转 int i=(int)m03.invoke(stu01,3,4); System.out.println(i); } }
四.通过反射获取成员变量
getField() 获取公开的成员变量
getDeclaredField() 获取私有的成员变量
在实体类中一定要有get和set方法,因为这串语句,在直观上通常以为是直接去找name属性,其实他是通过getName获取。
代码如下:
package com.yjx.test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test01 { public static void main(String[] args) throws Exception { //通过该类的权限命名获取Class对象 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student"); //通过类名.class获取到Class对象 Class<Student> clazz02=(Class<Student>)Student.class; //通过对象.getClass获取Class对象 Student stu=new Student(); Class<Student> clazz03=(Class<Student>)stu.getClass(); //通反射实例化,通过class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法 //无参构造就不传值进去 Constructor<Student> c01=clazz01.getConstructor(); //获取到Student对象 Student stu01=c01.newInstance(); stu01.setName("hhh"); stu01.setId(1); stu01.setAge(18); System.out.println(stu01); //反射读写属性 //在实体类中一定要有get和set方法,因为这串语句,我们通常以为是直接去找name属性,其实他是通过getName获取到该属性 Field f01=clazz01.getDeclaredField("name"); System.out.println(f01); f01.setAccessible(true); //这一串代码可以理解为Stundent.setName("哈哈哈") f01.set(stu01,"哈哈哈22"); System.out.println(stu01); //为什么我们要通过getName去获得属性,因为有可能我们在getName方法中做一些处理,如果直接通过name属性 //那么在getName中所定义的就没有意义,为了统一控制出口。 } }
今天的学习到此结束啦!!!