java——反射
什么是反射
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。反射也被称作框架设计的灵魂。
将类的各个组成部分封装为其他对象,这就是反射机制。
反射的功能
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
反射的好处就是:1.可以在运行过程中操作对象。2.可以解耦,提高程序的可扩展性。
解说一下
反射的概念太抽象,我刚开始接触的时候也是一脸懵逼,不知道到底是干什么的。在这里解说一下:
java代码在计算机中经历的三个阶段
源代码阶段
我们在写代码时,会先写好一个类,比如:
Person.java
public class Person {
private String name; // 成员变量
private int age;
public String a;
protected String b;
String c; // 默认defult
private String d;
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;
}
public Person() {}
public Person(String name, int age) { // 构造函数
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
public void eat() {
System.out.println("eat...");
}
}
以上就是我们平时写的一个代码。写完以后,我们可以通过java自带的编译器或者命令行“javac”来编译,在我们代码没有出现语法错误的情况下,会生成一个类文件“Person.class”存储在硬盘上。
Class对象阶段
类加载器(ClassLoader)将“Person.class”加载到内存里面。
在java中有Class类,就是用来描述所有字节码文件的一些共同的特征和行为。
——将成员变量封装为Field对象
——将构造方法封装为Constructor对象
——将成员方法封装为Method对象
在Class类中,用数组来描述所有的成员变量、构造方法、成员方法
运行阶段
创建对象
new Person
Class对象的功能
获取成员变量
Field[] getFields() 获取所有public 修饰的成员变量
import java.lang.reflect.Field;
public class ReflectDemo {
public static void main(String[] args) {
// 获取Person的Class对象
Class personClass = Person.class;
// 获取所有的成员变量
Field[] fields = personClass.getFields(); // 获取所有public 修饰的成员变量
for (Field field : fields) {
System.out.println(field);
}
System.out.println("-----------");
Field a = personClass.getField("a"); // 获取指定名称的public修饰的成员变量,会有返回值
Person p = new Person("Mike",18);
Object value = a.get(p);
System.out.println(value);
a.set(p,"路人甲");
System.out.println(p);
System.out.println("==================");
// 获取所有成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// 获取单个成员变量
Field d = personClass.getDeclaredField("d");
// 忽略访问权限修饰符的安全检查
d.setAccessible(true); // 暴力反射,无视修饰符,可以访问私有变量
Object value2 = d.get(p);
System.out.println(value2);
}
}
Field成员变量
操作:
1.设置值
get(Object obj)
2.获取值
set(Object obj,String name)
3.忽略访问权限修饰符的安全检查
setAccessible(true); 暴力反射
获取构造方法
import java.lang.reflect.Constructor;
public class ReflectMethod {
public static void main(String[] args) throws Exception {
Class personClass = Person.class;
// 语法:Constructor<T> getConstructor(类<?>……parameterTypes)
Constructor constructor = personClass.getConstructor(String.class,int.class);
System.out.println(constructor);
// 创建对象
Object person = constructor.newInstance("路人甲",18);
System.out.println(person);
System.out.println("-----------");
// // 空参情况下
// Constructor constructor1 = personClass.getConstructor();
// System.out.println(constructor1);
// Object person1 = constructor.newInstance();
// System.out.println(person1);
// // 暴力反射
// constructor1.setAccessible(true);
// // 使用空参数构造方法创建对象,操作可以简化成Class对象的newInstance方法
// Object o = personClass.newInstance();
// System.out.println(o);
Constructor declaredConstructor = personClass.getDeclaredConstructor(String.class,int.class);
System.out.println(declaredConstructor);
Constructor[] c = personClass.getConstructors();
for (Constructor cs : c ) {
System.out.println(cs);
}
}
}
获取成员方法
import java.lang.reflect.Method;
public class ReflectMethods {
public static void main(String[] args) throws Exception{
Class personClass = Person.class;
// 获取指定名称的方法
// 若有参数,还需要加上参数
Method eat_method = personClass.getMethod("eat"); // getMethod(name:"eat",String.class)
Person p = new Person("张飞",18);
// 执行方法
eat_method.invoke(p);
System.out.println("----------------");
// 获取所有public修饰的方法 包含自定义方法和object本身自带的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
// 获取方法名
String name = method.getName();
System.out.println(name);
// 支持暴力反射
}
// 获取类名
String className = personClass.getName();
System.out.println(className); // 获取全类名(包名。类名)
}
获取Class对象的方式
1.Class.forName(“全类名”):将字节码文件加载进内存,返回class对象。用在第一阶段。
2.类名.class:通过类名的属性class获取。在第二阶段使用
3.对象.getClass:封装在object类中。适用于已经有对象的情况下