一. 什么是反射?
概念:反射是java语言的一种机制,通过这种机制,可以动态的实例化对象、读取属性、调用方法。
二. 什么是类类
类类其实指的就是Java中的class类。
Class类是Java反射机制的核心,它用于表示一个类的字节码文件,也就是表示一个类的所有信息。
每个Java类都对应着一个Class对象,这个对象描述了该类的结构信息。它可以让程序在运行时获取类的名称、修饰符、父类、实现的接口、构造方法、字段、方法等类别信息。
三. 类类的获取方式
1.Class.forname(“类的全路径名”)
适用于从配置文件或其他动态输入中获取类的全限定名,动态加载类。
2.类实例.getclass()
适用于已经在程序中存在对象,需要获取该对象所属的类的Class对象。
3.类名.class
适用于在编写源代码时就已经确定要使用的类,且该类已经在代码中引用过。
实体类
package com.xissl.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()); } }
获取方式:
package com.xissl.reflect; /** * 类类(class类)的获取方式:一切反射的操作都从获取类对象开始 * 1.Class.forname * 2.类实例.getclass() * 3.类名.class * @author xissl */ public class Demo01 { public static void main(String[] args) throws Exception { Student stu = new Student(); //1.Class.forname 类的全路径名 Class class1 = Class.forName("com.xissl.reflect.Student"); System.out.println(class1); //2.类实例.getclass() 通用增删改 Class class2 = stu.getClass(); System.out.println(class2); //3.类名.class 通用查询 Class class3 = Student.class; System.out.println(class3); } }
四. 反射实例化
Java反射机制提供了通过Class对象实例化一个类的功能。这个功能的实现一般是通过Class类中的newInstance()方法来实现的。
1.无参构造器
newInstance()方法只能调用类的默认无参构造器,所以这种方式只能实例化没有参数的类。
2.有参构造器
如果想要调用有参构造器,使用getConstructor()方法获取Constructor对象,再用newInstance()方法来实例化有参数的类。
3.私有的有参构造器
如果要调用私有的有参构造器,可以使用getDeclaredConstructor()方法获取Constructor对象,然后,使用setAccessible()方法打开私有修饰符的访问权限,并使用newInstance()方法来实例化对象。
代码如下:
package com.xissl.reflect; import java.lang.reflect.Constructor; /** * 反射实例化 * 反射默认调用的是无参构造器 * @author xissl * */ public class Demo02 { public static void main(String[] args) throws Exception { Class class1 = Class.forName("com.xissl.reflect.Student"); //1.调用无参构造器反射实例化 Student s1 = (Student) class1.newInstance(); System.out.println(s1); //2.调用有一个参数的构造器实例化 //括号里面填的是参数的类别 Constructor cr1 = class1.getConstructor(String.class); Student s2 = (Student) cr1.newInstance("s001"); System.out.println(s2); //3.调用有两个参数的构造器实例化 Constructor cr2 = class1.getConstructor(String.class,String.class); Student s3 = (Student) cr2.newInstance("s002","nb"); System.out.println(s3); //4.调用私有的带一个参数的构造器实例化 Constructor cr3 = class1.getDeclaredConstructor(Integer.class); //打开私有修饰符的访问权限 cr3.setAccessible(true); Student s4 = (Student) cr3.newInstance(20); System.out.println(s4); } }
需要注意的是,调用私有构造函数可能会破坏封装性和安全性,所以建议在特定情况下再使用。
五. 反射动态方法调用
在Java中,方法是类的行为,定义了对象可以执行的操作。使用反射技术调用对象的方法,在不知道类信息的情况下,可以使程序更加灵活和智能。
使用反射机制动态调用对象的方法,一般是通过Method类中的invoke()方法来实现的。
1. 无参方法
通过getMethod()方法,先获取方法对象,再调用方法对象的invoke()方法。无参方法parameterTypes不需要写,直接删掉。
name: 要调用的方法名
parameterTypes:参数类型
obj:类实例
args:参数值
2.有参方法
通过getMethod()方法,先获取方法对象,再调用方法对象的invoke()方法。
3.私有的有参方法
如果方法是私有的或受保护的,也同样可以使用setAccessible()方法访问该方法。
六. 反射读写属性
在Java中,属性是对象的状态,定义了对象所具有的特征。使用反射机制读写对象的属性,在不知道类信息的情况下,可以使程序更加灵活和智能。
使用反射机制读写对象的属性,一般是通过Field类中的get()和set()方法来实现的。
package com.xissl.reflect; import java.lang.reflect.Field; /** * 反射读写属性 * @author xissl * */ public class Demo04 { public static void main(String[] args) throws Exception { //一切反射从类类开始 Class class1 = Class.forName("com.xissl.reflect.Student"); Student student = new Student("s001", "yh"); //写 Field snameField = class1.getDeclaredField("sname"); snameField.setAccessible(true); snameField.set(student, "sb"); //获取属性对象 读 Field[] f = class1.getDeclaredFields(); for (Field field : f) { field.setAccessible(true); System.out.println(field.getName()+":"+field.get(student) ); } } }
在使用反射读写对象的属性时,如果访问的属性是私有的或受保护的,也需要使用setAccessible()方法将其设置为可访问。