JavaSE基础回顾之反射知识点以及面试总结

1、Java反射机制概述

  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性以及方法
  • 加载完类之后,在堆内存的方法区中就会产生一个Class类型的对象clazz(一个类只有一个Class对象),该对象包含了完整的类的结构信息,我们可以通过clazz对象看到类的结构
    在这里插入图片描述

1.1、动态语言vs静态语言

  • 动态语言是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构
    • 主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。
  • 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。
    • Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!
  • 框架 = 反射 + 注解 + 设计模式

1.2、反射机制提供的功能

  • 在运行时 判断任意对象所属的类
  • 在运行时 构造任意类的对象
  • 在运行时 操作任意类所具有的成员变量和方法
  • 在运行时 调用任意对象的成员变量和方法
  • 在运行时 获取泛型信息
  • 在运行时 处理注解
  • 生成动态代理

1.3、相关API

  • java.lang.Class:反射的源头
  • java.lang.reflect.Method
  • java.lang.reflect.Proxy
  • java.lang.reflect.Field
  • java.lang.reflect.Constructor

1.4、反射实现的操作

  • 实体类Person
public class Person {
    private int pid;
    public String pname;
    int age;

    public Person() {
        System.out.println("无参构造器被调用...");
    }

    public Person(int pid, String pname, int age) {
        this.pid = pid;
        this.pname = pname;
        this.age = age;
    }

    private Person(String pname) {
        this.pname = pname;
    }

    private Person(int pid, String pname) {
        System.out.println("正在调用私有的构造方法...");
        this.pid = pid;
        this.pname = pname;
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "pid=" + pid +
                ", pname='" + pname + '\'' +
                ", age=" + age +
                '}';
    }

    private String showMsg(String msg){
        System.out.println("测试 使用反射调用对象的私有方法,+"+ msg+"!!");
        return "调用私有的showMsg()方法";
    }

    public void helloWays(){
        System.out.println("调用public修饰的方法...");
    }
}
  • 通过反射,创建Person类对象 以及 调用对象指定的属性和方法
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {

    // 在Person类外部,不可以通过Person类的对象调用其内部私有结构
    //  通过反射,调用对象的非私有属性和方法
    @Test
    public void test1() throws Exception {

        Class clazz = Person.class;
        // 1.通过反射,创建Person类对象
        Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class,int.class);
        Person person = (Person) constructor.newInstance(1213, "张三",26);
        System.out.println(person);

        // 如果调用私有的构造器来创建对象,会出现如下错误:
        // java.lang.NoSuchMethodException: com.xyl.javase.reflection.Person.<init>(int, java.lang.String)
        // Constructor constructor = clazz.getConstructor(int.class, String.class);
        // constructor.setAccessible(true);

        // 2.通过反射,调用对象指定的属性和方法
        Field pname = clazz.getDeclaredField("pname");

        // 调用属性 并设置值
        pname.set(person,"瑞.达利欧");
        System.out.println(person);

        // 调用方法
        Method helloWays = clazz.getDeclaredMethod("helloWays");
        helloWays.invoke(person);  // person.helloWays();
  /**
     * 疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?
     * 建议:直接new的方式。
     * 什么时候会使用:反射的方式。 反射的特征:动态性
     * 疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
     *    面向对象的封装性,主要体现在将属性和方法设置为私有的,使其在其他类中调用时无法访问该类中内部的        属性和私有方法,要想操作其私有属性或调用私有方法,则应该使用该类内部的public方法进行调用
     *    反射机制是动态的,可以调用私有方法,但是不建议
     */
    }
 }

2、理解Class类并获取Class实例

2.1、Class类的理解

  • 关于java.lang.Class类的理解,类的加载过程:
    • 程序经过Javac.exe命令后,会生成字节码文件(.class结尾),使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,该过程就称为类的加载加载到内存中的类,称为运行时类(Class类的一个实例)
    • 换句话说,Class实例对应着加载到内存中的一个运行时类
  • 创建Class对应运行时类的对象的通用方法:
Object obj = clazz.newInstance();  // 创建对应的运行时类的对象
// 1.必须有空参的构造器
// 2.权限修饰符的权限要求 要足够,通常设置为public

Class类的常用方法:
在这里插入图片描述

2.2、获取Class实例(四种方式)

    @Test
    public void test3() throws ClassNotFoundException {
        // Class实例对应着一个运行时类,该实例加载到内存后,会缓存一段时间
        //  即加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取运行时类

        // 方式1: 调用运行时类的class属性,如: XXX.class
        Class<Person> clazz1 = Person.class;
        System.out.println(clazz1);

        // 方式2: 通过运行时类的对象来调用 getClass()方法
        Person person = new Person();
        Class<? extends Person> clazz2 = person.getClass();
        System.out.println(clazz2);

       // 方式3: 调用Class的静态方法 Class.forName(String classPath),该方法也是反射动态性的体现
        //       classPath: 类的全路径
        Class<?> clazz3 = Class.forName("com.xyl.javase.reflection.Person");
        System.out.println(clazz3);

        System.out.println(clazz1 == clazz2);   // ==: 比较两个对象的内存地址是否相同
        System.out.println(clazz1 == clazz3);

        //  方式4: 使用类的加载器 loader.loadClass(classPath)  (方式4了解即可)
        ClassLoader loader = ReflectionTest.class.getClassLoader();
        Class<?> clazz4 = loader.loadClass("com.xyl.javase.reflection.Person");

        System.out.println(clazz4);
        System.out.println(clazz1 == clazz4);
    }

2.3、Class实例对应的结构

  • 哪些类型可以有Class对象?
    • (1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
    • (2)interface:接口
    • (3)[]:数组
    • (4)enum:枚举
    • (5)annotation:注解@interface
    • (6)primitivetype:基本数据类型
    • (7)void
      在这里插入图片描述

3、类的加载与ClassLoader

3.1、类的加载过程(广义)

  • 当程序主动使用某个类时,如果该类还未被就加载到内存中,则系统会通过类的加载(Load)、类的链接(Link)以及类的初始化(Initialize)来完成整个类的初始化
    在这里插入图片描述
  • 详细说明:
    在这里插入图片描述

3.2、理解ClassLoader

  • Java类编译、运行的执行流程
    在这里插入图片描述
  • 类加载器的作用是把类装载到内存中,即将class文件字节码的内容加载到内存中,并将这些静态数据转换为方法区的运行时数据结构,然后在堆中生成一个代表该类的java.lang.Class对象,作为方法区中类数据的入口
  • 标准的JavaSE类加载器可以根据要求查找类,但一旦某个类被装载到类加载器中,它将维持加载(缓存)一段时间,另外,JVM垃圾回收机制也可以回收这些Class对象
  • JVM 规范定义了如下类型的类的加载器:
    在这里插入图片描述
  • 代码说明:
import org.junit.Test;
public class ClassLoaderTest {

    @Test
    public void test1(){
        // 对于自定义类,使用系统类加载器进行加载
        ClassLoader classLoader1 = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader1);   //  sun.misc.Launcher$AppClassLoader@18b4aac2


        // 调用系统类加载器的getParent()方法,无法获取引导类加载器
        // 引导类加载器主要负责加载Java的核心类库,无法加载自定义类
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);   // sun.misc.Launcher$ExtClassLoader@63961c42

        ClassLoader classLoader3 = classLoader2.getParent();
        System.out.println(classLoader3);   // null

        ClassLoader classLoader4 = String.class.getClassLoader();
        System.out.println(classLoader4);   // null

    }
}

3.3、ClassLoader加载配置文件

  • 需要的配置文件所在的目录结构如下,userInfo1.properties在模块的src目录下,userInfo2.properties在模块的目录下:
    在这里插入图片描述
  • 其配置文件的内容如下:
uname=瑞.达利欧22
password=abc123
  • 代码示例:
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ClassLoaderTest {

     // Properties: 可用来读取配置文件
    // 使用IO流或反射读取配置文件
    @Test
    public void test2() throws IOException {
        Properties prop = new Properties();

        // 读取配置文件的方式1: IO流
        // 文件默认是在当前module目录下
//        FileInputStream fileInputStream = new FileInputStream("userInfo2.properties");
        FileInputStream fileInputStream = new FileInputStream("src\\userInfo1.properties");
//        prop.load(fileInputStream);

        // 读取配置文件的方式2: 使用ClassLoader
        // 配置文件的地址默认是在当前module的src目录下
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        InputStream inputStream = classLoader.getResourceAsStream("userInfo1.properties");
        prop.load(inputStream);

        String uname = prop.getProperty("uname");
        String password = prop.getProperty("password");
        System.out.println("uname = " + uname + ", password = " + password);
    }

}

4、创建运行时类的对象

  • 反射创建运行时类的对象
import org.junit.Test;
import java.util.Random;

public class NewInstanceTest {

    @Test
    public void test1() throws InstantiationException, IllegalAccessException {
        Class<Person> clazz = Person.class;
        // newInstance(): 调用该方法,创建运行时类的对象,内部会调用运行时类的无参构造器
        /*
        *  要想该方法可以正常地创建运行时类的对象,要求:
        *   1.运行时类必须提供空参的构造器
        *   2.空参构造器的访问权限符合访问要求,空参构造器通常设置为public
        *
        *  在Java Bean中要求提供一个public的空参构造器,原因:
        *   1.便于通过反射,创建运行时类的对象
        *   2.便于子类继承该运行类时,默认调用super()时,保证父类有此构造器
        * */
        Person person = clazz.newInstance();
        System.out.println(person);

    }
  }
  • 反射动态性的体现:需要在运行时才会知道到底创建的是哪个对象
    @Test
    public void test2(){
        for (int i = 1; i <= 20; i++) {
            // 根据生成的随机数,去创建对应的实例对象
            int num = new Random().nextInt(3); // 生成[0,3)区间的随机数
            String classPath = "";
            switch (num){
                case 0:
                    classPath = "java.util.Date";
                    break;
                case 1:
                    classPath = "java.lang.Object";
                    break;
                case 2:
                    classPath = "com.xyl.javase.reflection.Person";
                    break;
            }
            try {
                Object obj = getInstance(classPath);
                System.out.println(obj);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }


        }
    }

    public Object getInstance(String classPath) throws Exception {
        Class<?> clazz = Class.forName(classPath);
        return clazz.newInstance();
    }

5、获取运行时类的完整结构

5.0、前提数据准备

  • 创建自定义接口
public interface MyInterface {

    public void info();
}
  • 创建自定义注解
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "自定义注解";
}
  • 创建父类Creature
import java.io.Serializable;

public class Creature<T> implements Serializable {
    private String cname;
    public int age;
    double height;
    double weight;

    private void breath(){
        System.out.println("调用private修饰的私有方法breath(),呼吸中...");
    }
    public void eat(){
        System.out.println("调用public修饰的eat(),吃东西中...");
    }

    void play(){
        System.out.println("调用play()方法,玩耍中...");
    }
}
  • 创建子类Employee
import com.xyl.javase.reflection.Person;

@MyAnnotation(value = "Employee雇员类")
public class Employee extends Creature<String> implements Comparable<String>,MyInterface{

    private String name;
    int age;
    protected String email;
    public String address;

    public Employee(){ }

    @MyAnnotation(value = "私有的有参构造器")
    private Employee(String name){
        this.name = name;
    }

    Employee(String name,int age){
        this.name = name;
        this.age = age;
    }

    @MyAnnotation(value = "private修饰的showInfo()方法")
    private String showInfo(String nation){
        System.out.println("我的国籍:" + nation);
        return nation;
    }

    public String display(String interest){
        return interest;
    }

    @Override
    public void info() {
        System.out.println("调用info()方法");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }
}

5.1、获取类的属性(权限修饰符、数据类型、变量名)

@Test
public void test1(){
    Class<Employee> clazz = Employee.class;
    // 获取属性结构
    // getFields(): 获取当前运行时类及其父类中声明为public访问权限的属性
    Field[] fields = clazz.getFields();
    System.out.println("获取公有的属性:");
    for (Field field : fields) {
        System.out.println(field);
    }

    // getDeclaredFields(): 获取当前运行时类中声明的所有属性(不包含父类中声明的属性)
    System.out.println("获取全部的私有属性------");
    Field[] declaredFields = clazz.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println(declaredField);
    }
}
   @Test
    public void test2(){
        Class<Employee> clazz = Employee.class;

        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            // 1.获取权限修饰符
            int modifiers = field.getModifiers();
            // 2.获取数据类型
            Class<?> type = field.getType();
            // 3.获取变量名
            String name = field.getName();
            System.out.print(modifiers + " -- " + Modifier.toString(modifiers) + " -- " + type + " -- " + name);

            System.out.println();
        }
    }
  • test2()方法的输出结果如下:
 2 -- private -- class java.lang.String -- name
 0 --    -- int -- age
 4 -- protected -- class java.lang.String -- email
 1 -- public -- class java.lang.String -- address

注意:如上所示,访问修饰符由数字来表示,见源码Modifier类
在这里插入图片描述

5.2、获取类的方法

 @Test
    public void test2() {
        Class<Employee> clazz = Employee.class;

        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            //  1.获取方法声明的注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.print(annotation);
            }
            System.out.println();
            //  2.权限修饰符
            System.out.print(Modifier.toString(method.getModifiers()) + "\t");
            //  3.返回值类型
            System.out.print(method.getReturnType().getName() + "\t");
            //  4.方法名
            System.out.print(method.getName() + "\t");
            System.out.print("(");
            //  5.形参列表
            Class[] types = method.getParameterTypes();
            if (!(types == null && types.length == 0)) {  // 含参构造器
                int index = 0;
                for (int i = 0; i < types.length; i++) {
                    if (index == types.length - 1) {
                        System.out.println(types[i].getName() + "args" + i);
                        break;
                    }
                    System.out.print(types[i].getName() + "args" + i + ",");
                }
            }
            System.out.print(")");
            System.out.println();
        }
    }

5.3、获取类的构造器

@Test
public void test3() throws NoSuchMethodException {
    Class<Employee> clazz = Employee.class;

    // getConstructors(): 获取当前运行时类中声明为public的构造器
    Constructor[] constructors = clazz.getConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
    System.out.println("--------");
    //  getDeclaredConstructors(): 获取当前运行时类中声明的所有构造器
    Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
    for (Constructor cons : declaredConstructors) {
        System.out.println(cons);
    }
}

5.4、获取父类的基本信息

  • 获取运行时类的普通父类、带泛型的父类、带泛型父类的泛型
@Test
public void test1(){
    // 1. 获取运行时类的父类
    Class<Employee> clazz = Employee.class;
    Class<? super Employee> superclass = clazz.getSuperclass();
    System.out.println(superclass);   // class com.xyl.javase.reflection.structure.Creature

    // 2.获取运行时类的带泛型的父类
    Type genericSuperclass = clazz.getGenericSuperclass();
    System.out.println(genericSuperclass);  // com.xyl.javase.reflection.structure.Creature<java.lang.String>

    // 3.获取运行时类的带泛型 父类的泛型
   ParameterizedType paramType = (ParameterizedType) genericSuperclass;
    Type[] types = paramType.getActualTypeArguments();
    System.out.println(types[0].getTypeName());  // java.lang.String
}
  • 获取运行时类的接口
  @Test
    public void test2(){
        // 1.获取运行时类实现的接口
        Class<Employee> clazz = Employee.class;
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> interf : interfaces) {
            System.out.println(interf);
        }

        System.out.println("----------");
        // 2.获取运行时类的父类 实现的接口
        Class<?>[] interfaces2 = clazz.getSuperclass().getInterfaces();
        for (Class<?> inter : interfaces2) {
            System.out.println(inter);
        }
    }
  • 获取运行时类所在的包和接口
@Test
public void test3(){
    Class<Employee> clazz = Employee.class;
    // 1.获取运行时类的注解
    Annotation[] annotations = clazz.getAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println(annotation);
    }

    // 2.获取运行时类所在的包
    Package aPackage = clazz.getPackage();
    System.out.println(aPackage);
}

6、调用运行时类的指定结构

6.1、操作运行时类中的指定属性

@Test
public void test3() throws InstantiationException, IllegalAccessException, NoSuchFieldException {
    Class<Employee> clazz = Employee.class;

    // 创建运行时类的实例对象
    Employee employee = clazz.newInstance();

    // 1.getDeclaredField(String field): 获取运行时类中指定变量名的属性
    Field address = clazz.getDeclaredField("address");
    Field fname = clazz.getDeclaredField("name");

    // 2.setAccessible(boolean flag): 保证当前属性是可以被访问的
    fname.setAccessible(true);   // 访问私有属性时,需要设置对应的访问权限
    
    // 3.获取、设置指定对象的属性值
    fname.set(employee,"张三");
    address.set(employee,"高新路");

    System.out.println(address.get(employee));
    System.out.println(fname.get(employee));
}

6.2、操作运行时类中的方法

    @Test
    public void testMethod() throws Exception {
        Class<Employee> clazz = Employee.class;
        Employee employee = clazz.newInstance();

        // 获取指定的某个方法,
        // getDeclaredMethod()方法: 参数1,指明获取的方法名称; 参数2,获取方法的形参列表
        //   调用invoke方法,其返回值为 获取到的方法的返回值
        Method showInfo = clazz.getDeclaredMethod("showInfo", String.class);

        showInfo.setAccessible(true);
        // 调用invoke方法,其参数值1为 方法的调用者,参数2:给方法形参赋值的实参
        Object returnValue = showInfo.invoke(employee, "China");
        System.out.println(returnValue);

        System.out.println("如下调用私有的静态方法....");

        // private static void testPrivateAndStatic()
        Method method = clazz.getDeclaredMethod("testPrivateAndStatic");
        method.setAccessible(true);

        // 如果调用 运行时类中的方法没有返回值,则invoke()方法返回null
//        Object invoke = method.invoke(null);
        Object invoke = method.invoke(Employee.class);
        System.out.println(invoke);  // 无返回值,则返回null

    }

6.3、操作运行时类中的构造器

在这里插入图片描述

@Test
public void testConstructor() throws Exception {
    Class<Employee> clazz = Employee.class;

    // 1.获取指定的构造器
    //  getDeclaredConstructor(Class<?>... parameterTypes): 方法参数中需要传入构造器的参数类型
    Constructor<Employee> constructor = clazz.getDeclaredConstructor(String.class,int.class);

    // 2.保证此构造器是可被访问的
    constructor.setAccessible(true);
    // 3.调用对应的构造器,创建运行时类的对象
    Employee employee = constructor.newInstance("维克多.雨果", 26);

    System.out.println(employee);
}

7、反射的应用:动态代理

在这里插入图片描述
在这里插入图片描述
Spring中的IOC容器和AOP,IOC容器基于依赖注入实现,AOP基于动态代理来完成。

7.1、静态代理

  • 静态代理:代理类和被代理类 在编译期间就可以确定
public interface GoodsFactory {
    public void productGoods();
}
// 被代理类
public class AppleFactory implements GoodsFactory{

    @Override
    public void productGoods() {
        System.out.println("AppleFactory 开始生产 Apple ...");
    }
}
// 代理类
public class ProxyGoodsFactory implements GoodsFactory{

    private GoodsFactory goodsFactory;  // 用被代理类对象进行实例化

    public ProxyGoodsFactory(GoodsFactory goodsFactory) {
        this.goodsFactory = goodsFactory;
    }

    @Override
    public void productGoods() {
        System.out.println("代理工厂ProxyGoodsFactory 开始做些准备工作:");
        goodsFactory.productGoods();

        System.out.println("产品生产完成,接下来去执行首尾工作....");
    }

    public static void main(String[] args) {
        // 创建被代理类的对象
        AppleFactory appleFactory = new AppleFactory();

        // 创建代理类的对象
        ProxyGoodsFactory proxy = new ProxyGoodsFactory(appleFactory);

        proxy.productGoods();
    }
}

7.2、动态代理

  • 动态代理:代理类和被代理类在运行时动态确定
public interface Human {
    String getBelief();

    void eat(String food);
}
public class SuperMan implements Human{
    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃 " + food);
    }
}
  • 代理工厂
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactory {

    // 返回代理类对象
    public static Object getProxyInstance(Object obj){  // Obj: 被代理类的对象

        CustomInvocationHandler handler = new CustomInvocationHandler();
        Class<?> clazz = obj.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),handler);
    }
}

class CustomInvocationHandler implements InvocationHandler{

    private Object object; // 需要使用被代理类对象要调用的方法

    public void bind(Object object){
        this.object = object;
    }

    // 当通过代理类的对象,调用某方法时,就会自动调用如下的invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // method: 代理类对象调用的方法,也作为被代理对象要调用的方法
        // object: 被代理类的对象
        return method.invoke(object,args);
    }
}
  • 测试:
public class DynamicProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        // instance: 代理类的对象
        Human instance = (Human) ProxyFactory.getProxyInstance(superMan);
        // 当通过代理类对象调用方法时,会自动地调用被代理类中同名的方法
        instance.getBelief();
        instance.eat("极品佛跳墙");

        System.out.println("================");

        AppleFactory appleFactory = new AppleFactory();
        GoodsFactory goodsFactory = (GoodsFactory) ProxyFactory.getProxyInstance(appleFactory);

        goodsFactory.productGoods();
    }
}

7.3、动态代理与AOP

  • 前面介绍的Proxy和InvocationHandler,很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制
    在这里插入图片描述
    在这里插入图片描述
  • 改进后的说明:代码段1、代码段2、代码段3和深色代码段分离开了,但代码段1、2、3又和一个特定的方法A耦合了!最理想的效果是:代码块1、2、3既可以执行方法A,又无须在程序中以硬编码的方式直接调用深色代码的方法。
  • 使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的意义。通常都是为指定的目标对象生成动态代理
  • 这种动态代理在AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异:AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理。
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值