一.反射的概念
1.1什么是反射?
反射就是把Java类中的各种成分映射成一个个的Java对象。例如,一个类有:成员变量,方法,构造方法,包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。
1.2 反射常用类
- Class类—可获取类和类的成员信息
- Field类—可访问类的属性
- Method类—可调用类的方法
- Constructor类—可调用类的构造方法
** 1.3 使用反射的基本步骤**
1.导入java.lang.reflect.*
2.获得需要操作的类的Java.lang.Class对象
3.调用Class的方法获取Field、Method等对象
4.使用反射API进行操作(设置属性﹑调用方法)
二.Class类
2.1 Class类是反射机制的起源和入口
- 每个类都有自己的Class对象
- 提供了获取类信息的相关方法
- Class类继承自Object类
2.2 Class类存放类的结构信息
- 类名
- 父类﹑接口
- 方法﹑构造方法﹑属性
- 注释
2.3 获取Class类的三种方式
1.直接类型.class 例如:
Class<?> clazz1 = Student.class;//括号泛型可以写Student
2.先创建对象,然后用对象引用来创建
Student student=new Student();
Class<?> clazz = student.getClass();
3.Class.forName()创建(推荐使用)
Class<?> clazz2 = Class.forName("night.Student");//注意这里需要写入对象全路径名
2.4 获取类的其他结构
Class clazz = Class.forName("java.lang.Object");
Field fields[ ] = clazz.getDeclaredFields();//获取Field 对象 (即类的属性)
Method methods[] = clazz.getDeclaredMethods();//获取Method 对象 (方法)
Constructor constructors[] = clazz.getDeclaredConstructors();//获取Constructor对象 (构造方法)
下面来一段代码 帮助我们更好的理解反射:
public class Demo1 {
public static void main(String[] args) throws Exception{
//获取student的类对象(三种方式)
//方法一
Student student=new Student();
Class<?> clazz = student.getClass();
//方法二
Class<?> clazz1 = Student.class;
//方法三
Class<?> clazz2 = Class.forName("night.Student");
//获取clazz的带参构造方法
Constructor<?> constructor = clazz.getConstructor(String.class, int.class, String.class);
//使用带参构造创建对象
Object zhangsan = constructor.newInstance("张三", 23, "男");
//获取一个为无参的方法 Student中的show方法
Method show = clazz.getMethod("show");
//调用 zhangsan对象的show方法 相当于zhangsan.show();的写法
show.invoke(zhangsan);//姓名张三 年龄23 性别男
//这个方法是获取clazz本类中所有的私有方法,返回的是一个数组
// Method[] declaredMethods = clazz.getDeclaredMethods();
//获取clazz类中所有的公开方法,包括从父类中集成的方法 返回是一个数组
// Method[] declaredMethods = clazz.geMethods();
//获取本类中私有属性name 参数写属性的名字
Field name = clazz.getDeclaredField("name");
//若修改该类属性 必须调用.setAccessible(true) 设置成true 表示将私有修饰符去掉
name.setAccessible(true);
//这里相当于zhangsan.name="张三";
name.set(zhangsan,"张三");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(zhangsan,23);
Field sex = clazz.getDeclaredField("sex");
sex.setAccessible(true);
sex.set(zhangsan,"女");
//获取zhangsan的age属性 由于前面没有设置泛型因此返回的是Object类型 需要强转
// Integer age = (Integer) field.get(zhangsan);
System.out.println(zhangsan);
//下面两种输出是一样的
System.out.println(sex);
System.out.println(sex.get(zhangsan));
}
}
这是Student类
public class Student {
private String name;
private int age;
private String sex;
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Student() {
}
public void show(){
System.out.println("姓名"+name+" 年龄"+age+" 性别"+sex);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public static void print(){
System.out.println("这是一个静态方法");
}
public String printInfo(){
return name+" "+age+" "+" "+sex;
}
}
另外 当类中有静态方法和有带有返回值的方法时候 比如学生类中的 public static void print() 静态方法 在反射的时候 直接调用就行了 里面不用写对象引用 相当于Student.print(); 因为clazz就是Student的类对象嘛
Method print = clazz.getMethod("print");
print.invoke(null);
调用有返回值的方法 返回值类型不指定的话为Object类型
Method printInfo = clazz.getMethod("printInfo");
Object value = printInfo.invoke(zhangsan);//相当于 zhangsan.printInfo();
System.out.println(value);//打印的value值为方法返回的值