反射
1、反射概述
反射:框架设计的灵魂
- 框架:半成品软件。可以在框架的基础上进行软件的开发,简化代码。
- 反射:将类的各个组成部分封装为其他对象,这就是反射机制。
java代码的运行我们给它分为三个阶段
一、Source源代码阶段(在硬盘上存储,尚未进内存)
1.创建类文件。Student.java
2.编译 javac -->生成字节码文件 Student.class
- 成员变量
- 构造方法
- 成员方法
二、Class类对象阶段
将字节码文件加载进内存–>ClassLoader类加载器
将Student.class字节码文件加载进内存。在内存中会存在一个对象来描述这个文件 --> Class类对象。
Class类对象中存在通用的一些东西:成员变量、成员方法和构造方法。
成员变量封装为Field对象,使用数组来描述所有的成员变量Field[] fields
构造方法封装为Constructor对象,使用数组来描述所有的构造方法Constructor[] cons
成员方法封装为Method对象,使用数组来描述所有的成员方法
Method[] methods
三、Runtime运行时阶段。该阶段创建对象。new Student()
反射的好处:
- 在程序的运行过程中,操作这些对象。
- 可以解耦合,降低程序的耦合性,提高程序的可扩展性。
2、获取Class的三种方式
获取Class的三种方式
- 在源代码阶段:Class.forName(“全限定类名”):将字节码文件加载进内存,返回Class对象。
- 在Class类对象阶段:通过类名.class获取:通过类名的属性class来获取
- Runtime阶段:对象.getClass():getClass()方法在Object类中定义
代码实现:获取Class的三种方式
package com.yh.pojo;
public class Student{
private String name;
private int age;
public String sex;
public void study(){
System.out.println("study...");
}
public void study(String subject){
System.out.println("study:"+subject);
}
private void sleep(){
System.out.println("sleep...");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
private Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.yh.reflect;
import com.yh.pojo.Student;
public class ReflecDemo {
/**
* 获取Class的三种方式
*/
public static void main(String[] args) throws Exception {
//1.Class.forName("全限定类名")
Class class1 = Class.forName("com.yh.pojo.Student");
System.out.println(class1);
//2.类名.Class
Class class2 = Student.class;
System.out.println(class2);
//3.对象.getClass()
Student student = new Student();
Class class3 = student.getClass();
System.out.println(class3);
//比较三个对象的内存地址
System.out.println(class1==class2);//true
System.out.println(class1==class3);//true
}
}
结论:同一个字节码文件(*.class)在一次程序的运行中,只会被加载一次,都会生成且只会生成一个Class对象,不论通过哪一种方式获取的Class对象都是同一个。
3、使用Class对象
API方法的使用
1.获取成员变量
- Field[] getFields() :获取所有public修饰的成员变量
- Field getField(String name):获取指定名称的public修饰的成员变量
- Field[] getDeclaredFields():获取所有的成员变量(包含私有的成员变量)。
- Field getDeclaredField(String name):获取指定名称的成员变量(包括私有)。注意:操作私有成员变量时需要忽略访问权限修饰符的安全检查:.setAccessible(true);//暴力反射
成员变量的作用:
- 设置值。
- set(Object obj, Object value)
- 获取值
- get(Object obj)
public static void main(String[] args) throws Exception {
//1.获取Student的Class对象
Class studentClass = Student.class;
//2.获取所有public修饰的成员变量
Field[] fields = studentClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
//3.获取public修饰的指定的成员变量
Field sex = studentClass.getField("sex");
Student student = new Student();
//成员变量获取值
Object o = sex.get(student);
System.out.println(o);
//成员变量设置值
sex.set(student,"女");
System.out.println(student);
System.out.println("======================");
//获取所有的成员变量(包括私有的)
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//获取指定成员变量
Field name = studentClass.getDeclaredField("name");
Student s2 = new Student();
//忽略访问权限修饰符的安全检查
name.setAccessible(true);//暴力反射
name.set(s2,"张三");
System.out.println(s2);
}
2.获取构造方法
获取构造方法们
- Constructor<?>[] getDeclaredConstructors() :获取所有的构造函数(包括私有的)
- Constructor getDeclaredConstructor(类<?>… parameterTypes) :获取指定的构造函数(包括私有的)
- Constructor<?>[] getConstructors() :获取public修饰的所有的构造函数
- Constructor getConstructor(类<?>… parameterTypes) :获取public修饰的指定参数的构造函数
作用:创建对象
public static void main(String[] args) throws Exception {
//1.获取Student的Class对象
Class studentClass = Student.class;
//2.获取指定参数的构造方法
Constructor constructor = studentClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//使用有参构造创建对应的对象
Object student = constructor.newInstance("张三", 23);
System.out.println(student);
System.out.println("-----------------------");
//使用无参构造方法创建对象。
Constructor constructor1 = studentClass.getConstructor();
Object student1 = constructor1.newInstance();
System.out.println(student1);
//可以直接简化为Class对象的newInstance()
Object student2 = studentClass.newInstance();
System.out.println(student2);
System.out.println("========================");
//获取所有public修饰的构造函数
Constructor[] constructors = studentClass.getConstructors();
for (Constructor constructor2 : constructors) {
System.out.println(constructor2);
}
System.out.println("=====================");
//获取所有的构造函数(包括私有的)
Constructor[] declaredConstructors = studentClass.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
3.获取成员方法
- Method[] getMethods() :获取public修饰的成员方法(包括从父类及顶级父类Object中继承的public修饰的方法)
- Method getMethod(String name, 类<?>… parameterTypes) :获取public修饰的指定方法名和参数类型的成员方法
- Method [] getDeclaredMethods() :获取本类中所有的成员方法
- Method getDeclaredMethod(String name, 类<?>… parameterTypes) :获取本类中所有的指定方法名和参数类型的成员方法
public static void main(String[] args) throws Exception {
//1.获取Student的Class对象
Class studentClass = Student.class;
//2.获取public修饰的成员方法
Method study = studentClass.getMethod("study", null);
//执行方法: .invok()
Student student = new Student();
study.invoke(student,null);
System.out.println("===============");
//3.获取public修饰的带参方法
Method study1 = studentClass.getMethod("study", String.class);
//执行方法
study1.invoke(student,"java");
System.out.println("=========================");
//获取所有public修饰的方法:包括从父类继承的public修饰的方法
Method[] methods = studentClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("=======================");
//获取所有本类中声明的方法(包含私有的)
Method[] declaredMethods = studentClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
}