一. 什么是反射?
概念:反射是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()方法将其设置为可访问。