在初步学习框架的时候,了解到反射技术被常用于框架的底层设计,对此技术比较感兴趣,故写下此文.
反射技术能够做什么?
通常,想要实例化一个对象,必须通过new关键词创建对象并且创建出的对象不能调用其私有属性和私有方法,尤其是当该类将自己的构造方法私有,那new关键字就无法创建该类对象了,但是我就是想拿到它的私有属性,用它的私有方法,还想实例化该类对象就算他的构造器私有了,咋办呢?反射就可以解决这个问题.
反射的原理理解
反射将一个类的划分颠覆了我对类的认识,也让我对JAVA的面向对象思想理解的更深了一些.
我们之前理解的类就是有三大部分组成:构造方法,成员方法和成员变量.而以此为模板就可以new出该类对象 如 Car car = new Car(); 这里的car就是Car这个类的一个实例化对象.
而反射先找到该类字节码对象,再将类划分为构造方法对象,成员方法对象,成员变量对象(可能还有其他)。在拿到该类的字节码文件之后,通过反射,你可以拿到任何一个你想要的对象,整个类就像摆在你餐桌上的一道菜,你可以对它为所欲为。
原理实现以及代码展示
package service;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Demo {
//需求一:创建构造方法私有的Car对象
@Test
public void test01() throws Exception {
/*如果我们想使用下面的Car类,通常思路是new对象*/
//Car car = new Car("奔驰"); 这里是无法直接new的
//首先先解决实例化对象的问题
/*
三部曲:1、得到该类的字节码对象;2、通过字节码对象调用该类的成员对象;3、实现需求
*/
//一、得到该类的字节码对象
//方式1:类.class
Class<Car> carClass01 = Car.class;
//方式二: 对象.getClass() 这里仅写了私有的空参数构造,所以不能直接创建对象,不推荐,不做示范
// 方式三(推荐): Class.forName(类的全路径)
Class<?> carClass02 = Class.forName("service.Car");
//二、通过字节码对象调用该类的成员对象
Constructor<?> declaredConstructor = carClass02.getDeclaredConstructor();
//非常关键的步骤,设置权限为Accessible,默认是false,
//不修改的话会报java.lang.IllegalAccessException异常,无法使用私有成员
declaredConstructor.setAccessible(true);
Car car = (Car) declaredConstructor.newInstance();
car.setCarName("奔驰");
//打印仅是为确认创建了我们想要的对象
System.out.println(car);
}
//需求二:调用Car的run方法(私有方法)
//注意,因为调用的是私有方法,所以调用getDeclaredMethod()而不是getMethod(),后者只能调用非私有方法。
@Test
public void test02() throws Exception {
Class<?> carClass02 = Class.forName("service.Car");
Constructor<?> declaredConstructor = carClass02.getDeclaredConstructor();
//非常关键的步骤,设置权限为Accessible,默认是false,
//不修改的话会报java.lang.IllegalAccessException异常,无法使用私有成员
declaredConstructor.setAccessible(true);
Car car = (Car) declaredConstructor.newInstance();
Method run = carClass02.getDeclaredMethod("run", String.class);
run.setAccessible(true);
run.invoke(car, "宾利");
}
//需求三:调用Car的私有属性
@Test
public void test03() throws Exception {
Class<?> carClass02 = Class.forName("service.Car");
Constructor<?> declaredConstructor = carClass02.getDeclaredConstructor();
//非常关键的步骤,设置权限为Accessible,默认是false,
//不修改的话会报java.lang.IllegalAccessException异常,无法使用私有成员
declaredConstructor.setAccessible(true);
Car car = (Car) declaredConstructor.newInstance();
Field carName = carClass02.getDeclaredField("carName");
carName.setAccessible(true);
carName.set(car, "柯尼塞格");
System.out.println(car);
}
}
class Car {
//将两个成员属性私有
private String carName;
private double price;
//私有化有参构造,这个时候直接new对象已经不行了
private Car() {
}
//一个私有方法
private void run(String car) {
System.out.println(car + "汽车行驶");
}
//setter 和 getter方法 和toString方法
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"carName='" + carName + '\'' +
", price=" + price +
'}';
}
}