目录
一,反射的定义
Java反射是指在运行时获取一个类的信息并操作该类的成员(字段、方法、构造函数等)的能力。
这里我们就要谈谈java的运行期和编译期指的是什么:
1.编译期:将磁盘里的java源文件编译成字节码文件,编译期只是做了一些翻译功能,并没 有把代码放在内存中运行起来。
2.运行期:java虚拟机会将磁盘里的字节码文件转换成机器码,交给 计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码 放到 内存中执行起来。
二,反射的用途
通过反射,我们可以在运行时动态地创建对象、调用方法、访问字段等,而不需要在编译时确定这些操作。
三,反射的基础知识
1.获取Class对象:可以通过对象的getClass()方法或者类名.class来获取一个类的Class对象,也可以通过Class.forName("类名")来获取某个类的Class对象。
Class常用方法 :
类型 | 访问方法 | 返回值类型 | 说明 | |||
---|---|---|---|---|---|---|
包路径 | getPackage() |
| 获取该类的存放路径 | |||
类名称 | getName() |
| 获取该类的名称 | |||
继承类 | getSuperclass() | Class 对象 | 获取该类继承的类 | |||
实现接口 | getlnterfaces() |
| 获取该类实现的所有接口 | |||
构造方法 |
|
| 获取所有权限为 public 的构造方法 获取当前对象的所有构造方法 | |||
方法 | getMethods() getDeclaredMethods() | Methods 型数组 Methods 对象 | 获取所有权限为 public 的方法 获取当前对象的所有方法 | |||
成员变量 |
| Field 型数组
| 获取所有权限为 public 的成员变量
|
2.创建对象:通过Class对象的newInstance()方法可以创建一个类的实例,相当于调用了该类的无参构造函数。如果需要调用有参构造函数,可以通过先获取构造函数对象再调用newInstance()方法来实现。
public class Demo15 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class cls = Order1.class;
Order1 order = (Order1)cls.newInstance();
System.out.println(order);
Constructor con = cls.getConstructor(int.class);
Order1 order2 = (Order1)con.newInstance(100);
System.out.println(order2);
}
}
class Order1{
private String orderNo;
private LocalDateTime time;
public Order1() {
this.orderNo = UUID.randomUUID().toString();
this.time = LocalDateTime.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Order1(int a) {
System.out.println("这是Order类的有参构造");
}
@Override
public String toString() {
return "Order [orderNo=" + orderNo + ", time=" + time + "]";
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public LocalDateTime getTime() {
return time;
}
public void setTime(LocalDateTime time) {
this.time = time;
}
}
3.访问字段:通过Field类的对象可以访问某个类的字段。可以使用getDeclaredFields()方法获取所有字段的数组,然后通过Field对象的get()和set()方法来读取和修改字段的值。
// 反射操作 访问字段(成员变量)
public class Demo07 {
public static void main(String[] args) {
Class cls = Book.class;
// 所有Public访问修饰符
//Field[] fields = cls.getFields();
Field[] fields = cls.getDeclaredFields();
for(Field f : fields) {
System.out.println("成员变量访问修饰符(int):"+f.getModifiers());
System.out.println("成员变量访问修饰符:"+Modifier.toString(f.getModifiers()));
System.out.println("成员变量类型:"+f.getType());
System.out.println("成员变量名称:"+f.getName());
}
}
}
class Book{
public String bookName;
public int count;
private double prince;
private String address;
public Book() {
}
public void dosth(int a, double b, String c) {
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getPrince() {
return prince;
}
public void setPrince(double prince) {
this.prince = prince;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Book [bookName=" + bookName + ", count=" + count + ", prince=" + prince + ", address=" + address + "]";
}
}
3.调用方法:通过Method类的对象可以调用某个类的方法。可以使用getDeclaredMethods()方法获取所有方法的数组,然后通过Method对象的invoke()方法来调用具体的方法。
// 反射操作(获取方法)
// 每一个方法都会被封装成一个Method对象。
public class Demo10 {
public static void main(String[] args) {
Class cls = Book.class;
// 包含父类中的方法
// Method[] methods = cls.getMethods();
// 获取所有定义的方法(仅包含当前类)
Method[] methods = cls.getDeclaredMethods();
for(Method m : methods) {
System.out.println(m.getName());
System.out.println(Modifier.toString(m.getModifiers()));
System.out.println();
// 获取所有参数类型
//Class[] paraType = m.getParameterTypes();
Parameter[] paraType = m.getParameters();
for(Parameter p : paraType) {
System.out.println(p.getName());
System.out.println(p.getType());
System.out.println("----------------------");
}
}
}
}
4.获取父类和接口:通过Class对象的getSuperclass()方法可以获取一个类的父类,通过getInterfaces()方法可以获取一个类实现的接口。
5.修饰符和注解:通过Class对象可以获取一个类的修饰符(如public、private等)和注解信息。返回方法的修饰符,它是一个 int ,不同的 value 表示不同的访问修饰符。
四,代理模式
给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型 设计模式。
1,静态代理
静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
如上图所示的代码实现如下:
public class Client {
public static void main(String[] args) {
Subject subject = new SubjectProxy();
subject.request();
}
}
public interface Subject {
void request();
}
public class RealSubject implements Subject{
public RealSubject() {}
@Override
public void request() {
System.out.println("业务逻辑1");
System.out.println("业务逻辑2");
System.out.println("业务逻辑3");
}
}
public class SubjectProxy implements Subject{
private Subject terget;
public SubjectProxy() {
terget = new RealSubject();
}
public void request() {
System.out.println("begin-------------");
terget.request();
System.out.println("end---------------");
}
}
运行结果如下:
2,动态代理
代理类在程序运行时创建的代理方式被成为动态代理。
我们上面静态代理的例子中,代理类(SubjectProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。 比如说,想要在每个代理的方法前后都加上一个处理方法。
public class Client {
public static void main(String[] args) {
// 将创建被代理的对象(UserService接口的实现类)传入我们动态代理的方法中
LogInvocationHandlerImpl hander = new LogInvocationHandlerImpl(new UserServiceImpl());
LogInvocationHandlerImpl hander1 = new LogInvocationHandlerImpl(new RealSubject());
// 创建目标对象
RealSubject realSubjectTagter = new RealSubject();
// 创建UserService动态代理对象
UserService proxy = (UserService)Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[] {UserService.class},
hander);
Subject proxy1 = (Subject)Proxy.newProxyInstance(
realSubjectTagter.getClass().getClassLoader(),
realSubjectTagter.getClass().getInterfaces() ,
hander1);
proxy.select();
proxy1.request();
System.out.println(proxy.getClass());
System.out.println(proxy1.getClass());
}
}
// InvocationHandler接口的实现类:代理类中扩展逻辑,抽取封装
public class LogInvocationHandlerImpl implements InvocationHandler {
private Object tager;
public LogInvocationHandlerImpl(Object tager) {
this.tager = tager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("%s方法开始--------------\n",method.getName());
// 执行目标对象的目标方法(反射)
Object returnValue = method.invoke(tager, args);
System.out.printf("%s方法结束--------------\n",method.getName());
return returnValue;
}
}
// 真正的实现类
public class UserServiceImpl implements UserService {
@Override
public void select() {
System.out.println("select * ..................");
System.out.println("数据库中完成用户信息的查询执行!");
}
@Override
public void update() {
System.out.println("update ...................");
System.out.println("数据库中用户状态的更新执行!");
}
}
public interface UserService {
void select();
void update();
}