学习java深度学习,提升编程思维,适合掌握基础知识的工作者学习

1.反射和代理

1.1 概念介绍

在Java编程中,反射和代理是两个强大的特性,能够在运行时动态地操作和扩展类的行为。通过反射,我们可以在不知道类的具体信息的情况下操作类的属性和方法;而代理则允许我们创建一个代理类来拦截并增强目标对象的行为

1.2应用场景

像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。
但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制,掌握反射和代理机制,有利于我们了解这些框架的内核原理,提升编程思维

  • xml的bean配置的注入
  • AOP拦截
  • 数据库事务
  • springMVC
  • Java注解
  • 开发工具如IDEA,提供一个类的属性方法展示给我们智能快捷选择

这些内核都是反射和代理机制在其作用

1.3 反射-reflect

由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。这种通过Class实例获取class信息的方法称为反射(Reflection)。

准备工作

Food.java

public class Food {
    private Integer id;
    private  String name;
   // ....省略get set 等
}

1.3.1 获得类-Class

获得类有三种方式,看代码演示

 /***
     * @Description: 得到Class
     */
    @Test
    public void t1() throws ClassNotFoundException {
        Class cls=null;
        //1.通过类名直接获得
        cls= Food.class;
        //2.通过实例获得
        cls=new Food(1, "火锅").getClass();
        //3.通过路径+类名的字符串获得
        cls=Class.forName("com.jsoft.reflection.Food");
        printClassInfo(cls);


    }

    /***
     * @Description: 读取类的信息

     */
    static void printClassInfo(Class cls) {
        System.out.println("Class name: " + cls.getName());
        System.out.println("Simple name: " + cls.getSimpleName());
        if (cls.getPackage() != null) {
            System.out.println("Package name: " + cls.getPackage().getName());
        }
        System.out.println("is interface: " + cls.isInterface());
        System.out.println("is enum: " + cls.isEnum());
        System.out.println("is array: " + cls.isArray());
        System.out.println("is primitive: " + cls.isPrimitive());
    }

打印效果

Class name: com.jsoft.reflection.Food
Simple name: Food
Package name: com.jsoft.reflection
is interface: false
is enum: false
is array: false
is primitive: false

1.3.2 获得类的字段-Field

演示代码

public class Father  extends Man{
    private Integer age;
    public  String job;

}

public class Man{
    private Integer id;
    private String name;
    public String address;
    }

对任意的一个Object实例,只要我们获取了它的Class,就可以获取它的一切信息。
我们先看看如何通过Class实例获取字段信息。Class类提供了以下几个方法来获取字段:

注意:
Declared修饰就只管当前类字段,和private、public无关
否则就包含父类的public

测试代码

 @Test
    public void t2() throws NoSuchFieldException {
       Class cls= Father.class;
       //1.得到当前类的所有字段,不包含父类
       Field[] fs=cls.getDeclaredFields();
        System.out.println("1.得到当前类的所有字段,不包含父类");
        for (Field f : fs) {
            printFeild(f);
        }
        //2.得到当前类某个字段
        System.out.println("2.得到当前类某个字段,不包含父类");
       Field f=cls.getDeclaredField("job");
        printFeild(f);

        //3.得到当前类及父类的所有public字段
        System.out.println("3.得到当前类及父类的所有public字段");
        fs=cls.getFields();
        for (Field f1 : fs) {
            printFeild(f);
        }

        //4.得到当前类及父类的public字段
        System.out.println("4.得到当前类及父类的public字段,如果是private,则要报错");
        f=cls.getField("address");
        printFeild(f);

    }

    /***
     * @Description: 打印字段信息
     */
    public  void printFeild(  Field f){
        System.out.println("//------------字段信息 start");
        System.out.println("字段名称:"+f.getName());
        System.out.println("字段类型:"+f.getType().getName());

        int m = f.getModifiers();
        System.out.println("field is final:"+Modifier.isFinal(m));; // true
        System.out.println("field is Public:"+Modifier.isPublic(m));; // true
        System.out.println("field is Protected:"+Modifier.isProtected(m));; // true
        System.out.println("field is Private:"+Modifier.isPrivate(m));; // true
        System.out.println("field is Static:"+Modifier.isStatic(m));; // true

        System.out.println("//------------字段信息 end");
    }

1.3.3 动态访问和修改对象实例的字段

  @Test
    public void t3() throws NoSuchFieldException, IllegalAccessException {
        Food food=new Food(1, "火锅");
        System.out.println("food.getName:"+food.getName());
        Class cls=food.getClass();
        Field f=cls.getDeclaredField("name");
        f.setAccessible(true); //不设置这个private 字段要抛出异常
        //通过field获得值
        Object name= f.get(food);
        System.out.println("name:"+name);
        //通过field设置值
        f.set(food, "西北风");
        System.out.println("name:"+food.getName());
    }

1.3.4 获得类方法-Method

示例代码

@Data
public class Father  extends Man{
    private Integer age;
    public  String job;
   public  String play(int type){
        System.out.println("param value:"+type);
        return type+"";
    }

    public  String sleep(String type, Date date){
        System.out.println("param value type:"+type+";date:"+date);
        return type+"";
    }
    private  void self(){
        System.out.println("this is private method");
    }
	public void dd(){
        System.out.println("没有参数方法()");
    }


}

@Data
public class Man{
    private Integer id;
    private String name;
    public String address;

    @Override
    public Food eat() {

        return new Food(1,"火锅");
    }
}

测试代码

@Test
    public void t4() throws IllegalAccessException, NoSuchMethodException {
        Class cls= Father.class;
        System.out.println("1. 获取所有public的Method(包括父类)");
         Method[] methods=cls.getMethods();
        for (Method method : methods) {
            printMethod(method);
        }
        System.out.println("2. 获取某个public的Method(包括父类)");
        //第一个参数为方法名,第二参数是可变参数,传递方法的参数类型,如果无参数则不传递
        Method m= cls.getMethod("getName");
        printMethod(m);
        //方法有1个参数
        //注意int foat double这些基本类型对用的类是int.class,不是Integer.class
        m=cls.getMethod("play", int.class);
        printMethod(m);
        //方法有多个参数
        m=cls.getMethod("sleep", String.class, Date.class);
        printMethod(m);

        System.out.println("3. 获取当前类的的Method(不包括父类)");
        m= cls.getDeclaredMethod("getJob");
        printMethod(m);
        //私有方法也可以
        m= cls.getDeclaredMethod("self");
        //父类方法不可以,要报java.lang.NoSuchMethodException
        m= cls.getDeclaredMethod("eat");
        printMethod(m);

     printMethod(m);
    }

    public void printMethod(Method addMethod){
        System.out.println("---------方法名称: 【" + addMethod.getName()+"】---相关属性------------");
        System.out.println("修饰符: " + Modifier.toString(addMethod.getModifiers())); //public private等
        System.out.println("返回值: " + addMethod.getReturnType()); //返回值类型的class数组
        Class[] paramsCls= addMethod.getParameterTypes(); //参数值类型对应的class数组
    }

1.3.5 调用方法.invoke

代码

@Test
    public void t5() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Father father=new Father();
        Class cls= father.getClass();
        Method m=null;

        //无参无返回方法
        m=cls.getMethod("dd");
        m.invoke(father);

        //有参数,有返回值
        m=cls.getMethod("sleep", String.class,Date.class);
       String ret=(String)m.invoke(father, "1",new Date());
        System.out.println("返回值:"+ret);

        //private方法调用
        m=cls.getDeclaredMethod("self");
        //私有方法必须设置为m.setAccessible(true);
        m.setAccessible(true);
        m.invoke(father);

    }

jdk内置对象的方法调用的另外一种写法

  @Test
    public void t6() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
       String s="abcde";
       String sub=s.substring(0,2);
        System.out.println(sub);
        //通过类加载
        Class   cls=String.class;
        Method method=cls.getMethod("substring",int.class,int.class);
       sub=(String) method.invoke(s, 0,2);
        System.out.println(sub);

    }

其实就相当于

1.3.6 类实例化-构造函数Constructor

准备类

public class Const {
    private Integer id;
    private String name;

    public Const() {
        System.out.println("无参数构造方法");
    }

    public Const(Integer id, String name) {
        System.out.println("有参数构造方法");
        this.id = id;
        this.name = name;
    }
}

Class.newInstance()

  @Test
    public void t7() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
       Class cls =Class.forName("com.jsoft.reflection.Const");
        Const aConst = (Const) cls.newInstance();
        
    }

Class.newInstance()最大的问题是只能实例化无参的构造方法,如果我们把无参构造方法屏蔽掉,代码会出错,所以我们需要使用Constructor类来实现有参的构造方法

代码示例

    @Test
    public void t8() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class cls =Class.forName("com.jsoft.reflection.Const");
        //得到所有构造函数
        Constructor[] constructors=  cls.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("修饰符: " + Modifier.toString(constructor.getModifiers()));
            System.out.println("构造函数名: " + constructor.getName());
            System.out.println("参数列表: " );
            Class[] cs= constructor.getParameterTypes();
            for (Class c : cs) {
                System.out.println(c.getName());
            }
        }

        //获得具体一个(无参)
        Constructor cst=cls.getConstructor();
        //newInstance实例化
        Const const1=(Const) cst.newInstance();

        //获得具体一个(有参)
         cst=cls.getConstructor(Integer.class,String.class);//传入构造函数的参数的类型
        //newInstance实例化
         const1=(Const) cst.newInstance(1,"蒋增奎");
    }

1.3.7 instanceof

class Person{
}

class Teacher extends Person{
}

class Student extends Person{
}

测试

public class test01 {
    public static void main(String[] args) {
 
        Object obj = new Student(); // 主要看这个对象是什么类型与实例化的类名
        System.out.println(obj instanceof Student); // true
        System.out.println(obj instanceof Person); // true
        System.out.println(obj instanceof Object); // true
        System.out.println(obj instanceof String); // false
        System.out.println(obj instanceof Teacher); // false  无关系
        System.out.println("========================");

        Person person = new Student();
        System.out.println(person instanceof Person); // true
        System.out.println(person instanceof Object); // true
        // System.out.println(person instanceof String); // 编译错误
        System.out.println(person instanceof Teacher); // false 无关系

    }
}

1.3.8 利用反射来解析spring配置

<bean id="employee" class="com.jsoft.po.Employee">
    <property name="id" value="1" />
    <property name="name" value="蒋增奎" />
    <property name="deptId" value="001" />
</bean>

解析思路

1.4 代理-proxy

1.4.1 代理模式

代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

举个例子:
boy向girl求婚
(1)现代:boy和girl直接发生通信,girl迫不及待的同意了
(2)古代:boy不能直接和girl发生关系,需要通过媒婆,boy向媒婆发起请求,媒婆转告girl,gilr同意,媒婆觉得女孩如果同意,婚前应该收彩礼10万,婚后不能家暴,媒婆就是代理,在原始的反馈上增加了自己的要求,提升了框架的健壮性。
java进阶学习笔记-LMLPHP
代理分为静态代理和动态代理两种类型

1.4.2 准备工作

public interface Love {

    /***
     * @Description: 结婚请求
     */
    public void marray();
      /***
     * @Description: 睡觉请求
     */
    public void sleep();
    public String like(int type);
    public int saveMoney(int money);
}


/**
接口实现类
**/
public class LoveImpl implements Love {
    @Override
    public void marray() {
        System.out.println("我同意");
    }
 	public void sleep() {
        System.out.println("我同意");
    }
    
    public String like(int type){
    	if(type==1)
            return "69";
        return "96";
    }
   @Override
    public int saveMoney(int money) {
        return money*10;
    }
}



1.4.3 静态代理

代码:

//代理类要实现接口
public class LoveProxy implements Love {
    private Love target;//代理的接口
    /***
     * @Description: 构造方法注入代理的接口
     */
    public LoveProxy(Love love){
        target=love;
    }

    @Override
    public void marray(){
        System.out.println("============代理marray方法");
        System.out.println("要彩礼10万");
        target.marray();
        System.out.println("不能家暴");
    }

    public void sleep(){
        System.out.println("============代理sleep方法");
        System.out.println("安全措施");
        target.sleep();

    }

    public String like(int type){
        System.out.println("============代理like方法");
        System.out.println("注意身体");
        return target.like(type);
    }


    public static void main(String[] args) {
        //实际应用:代理的应用
        Love love=new LoveImpl();
        LoveProxy proxy=new LoveProxy(love);
        proxy.marray();
        proxy.sleep();
        System.out.println( proxy.like(1));

    }


}

效果:在以前的需求上扩展了功能

============代理marray方法
要彩礼10万
我同意
不能家暴
============代理sleep方法
安全措施
我同意
============代理like方法
注意身体
69

总结:代理模式的实现

1.5 动态代理

静态代理:通过手动编写代理类来实现,需要为每个目标对象编写一个代理类。
动态代理:通过Java提供的相关接口和类,在运行时动态生成代理类,无需手动编写代理类。

我们仍然先定义了接口,但是我们并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。

动态代理三个重要的java类

1.5.1 InvocationHandler介绍

代理实例的调用处理器需要实现InvocationHandler接口,并且每个代理实例都有一个关联的调用处理器。当一个方法在代理实例上被调用时,这个方法调用将被编码并分派到其调用处理器的invoke方法上。
接口里最重要的方法invoke

  public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

其有三个参数,分别为:
proxy:是调用该方法的代理实例,是java在编译环节自动生成的,对开发者没有意义,如:jdk.proxy1.$Proxy0,注意不是代理的目标类,也不是接口。

method:是在代理实例上调用的接口方法对应的Method实例。

args:一个对象数组,其中包含在代理实例上的方法调用中传递的参数值,如果接口方法不带任何参数,则为 null。基元类型的参数包装在相应基元包装类的实例中,例如 java.lang.Integer 或 java.lang.Boolean

返回值:调用代理实例上的方法的返回值。
如果接口方法声明的返回类型是基元类型,那么该方法返回的值必须是对应基元包装类的实例;
否则,它必须是可分配给声明的返回类型的类型。如果此方法返回的值为 null,并且接口方法的返回类型为基元,则代理实例上的方法调用将引发 NullPointerException。如果此方法返回的值与接口方法的声明返回类型不兼容(如上所述),则代理实例上的方法调用将引发 ClassCastException

这里最重要的参数是method,可以通过moth.invote调用目标对象的方法

1.5.2 Proxy类

Proxy类提供了创建动态代理类及其实例的静态方法,该类也是动态代理类的超类,其最主要的方法是一个newProxyInstance的静态方法

   public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
                                          {......}

参数说明:
ClassLoader :
对应代理目标类对应的类加载器
Class<?>[] interfaces
目标代理类的接口类对应的CLASS,代理目标类的接口可以是多个
InvocationHandler h
要调用的处理器
返回对象:
返回实例,Object可以转化成对应的目标代理类的接口

1.5.3动态代理类的实现

准备代码:为了增加效果,我们在增加一个类和接口

public interface LifeService {
    public String eat(String name);

    public String drink(String name);
    public int like(int type);

}

public class Life implements LifeService {

    public String eat(String name){
        String ret="I like eat:"+name;
        System.out.println(ret);
        return ret;
    }

    public String drink(String name){
        String ret="I like drink:"+name;
        System.out.println(ret);
        return ret;
    }

    public int like(int type){
        String ret="mylike:"+type;
        System.out.println(ret);
        return type;
    }


}

自己做一个调度类,继承InvocationHandler

//自己编写处理器
public class MyHandler implements InvocationHandler {
    private  Object target;//代理的目标类

    //通过构造方法注入代理的目标
    public MyHandler(Object target){
        this.target=target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //给所有方法加上日志
        System.out.println("给大家增加一个log日志...........");
        String mName=method.getName();
        //给以save开头的方法名添加事务
        if(mName.length()>=4 && "save".equals(mName.substring(0,4))){
            System.out.println("开启事务...............");
        }
        //方法名是sleep的增加安全措施
        if("sleep".equals(mName)){
            System.out.println("注意安全措施...............");
        }
        //调用目标代理类的方法并返回方法返回值
        return method.invoke(target,args);
    }


}

封装一个调度工厂

public class ProxyFactory {

    /***
     * @Description: 动态代理工厂
     * @Create:2023/12/24 12:43
     * @Param: [target:代理的对象实例
     * @Return: java.lang.Object  代理接口对象
     */
    public static Object creatProxy(Object target){
        //动态调用代理
        return  Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  //目标的加载
               target.getClass().getInterfaces(), //目标类的接口的class,可以是多个,数组,如果指定,则要使用new Class[...]
                new MyHandler(target));
    }
    public static void main(String[] args) {

        //应用1
        Love love=(Love)creatProxy(new LoveImpl() );
        love.marray();
        love.sleep();
        int money=love.saveMoney(10);
        System.out.println("存钱:"+money);

        //应用2
        LifeService lifeService=(LifeService)creatProxy(new Life());
        lifeService.eat("火锅");
        lifeService.drink("可乐");

    }
}

执行效果:

给大家增加一个log日志...........
我同意
给大家增加一个log日志...........
注意安全措施...............
我同意
给大家增加一个log日志...........
开启事务...............
存钱:100
给大家增加一个log日志...........
I like eat:火锅
给大家增加一个log日志...........
I like drink:可乐

1.5.4动态实现接口

有时候,我们不想为接口单独做一个实现类,我们可以通过动态代理来实现,这个在springboot里面非常常见的编程思想

public class DynamicProxy {
    public static void main(String[] args) {
        //定义一个InvocationHandler对象,但不传入实现类,相当于
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              
                if (method.getName().equals("marray")) { //这个方法去实现,和做一个实现类原理一致
                    System.out.println("我同意个锤子");
                }
                return null;
            }
        };
        Love love = (Love) Proxy.newProxyInstance(
                Love.class.getClassLoader(), // 传入ClassLoader
                new Class[] { Love.class }, // 传入要实现的接口
                handler); // 传入处理调用方法的InvocationHandler
        System.out.println("3333");
        love.marray();
        

    }
}

1.5.4替换某个方法

在大量的java框架中,某种功能有默认实现,我们想替换掉,自己定义实现,其他方法不变,我们也可以使用动态代理技术实现。

public class ProxyReplcae {
    public static void main(String[] args) {
        LoveImpl loveImp=new LoveImpl();//默认实现,在spring里一般采用注入
        //定义一个InvocationHandler对象
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //这个对象不想使用以前实现,自定义实现
                if (method.getName().equals("marray")) {
                    System.out.println("不同意结婚");
                    return null;
                }
                else
                    return method.invoke(loveImp,args); //其他的依然使用默认实现

            }
        };

        Love love = (Love) Proxy.newProxyInstance(
                Love.class.getClassLoader(), // 传入ClassLoader
                new Class[] { Love.class }, // 传入要实现的接口
                handler); // 传入处理调用方法的InvocationHandler

        love.marray();  //已经使用自定义
        love.sleep();//依然是默认实现
    }


}

1.5 动态代理框架CGLIB

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。
为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

1.5.1 使用介绍

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>

public class MyDay {
    public void work(int hour){
        System.out.println(hour+"点开始工作");
    }

    public void sleep(int hour){
        System.out.println(hour+"点开始睡觉");
    }
}

代码


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * @class: com.jsoft.reflection.CglibProxyFacory
 * @description:
 * @author: jiangzengkui
 * @company: 教育家
 * @create: 2023-12-24 15:29
 */
public class CglibProxyFacory {
    /***
     clazz:代理目标类的class
     */
    public static Object getProxy(Class<?> clazz) {
        //自定义一个拦截器

        MethodInterceptor me=new MethodInterceptor(){

            /**
             * @param o           被代理的对象(需要增强的对象)
             * @param method      被拦截的方法(需要增强的方法)
             * @param args        方法入参
             * @param methodProxy 用于调用原始方法
             */
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)
                    throws Throwable {
                System.out.println("before method " + method.getName());
                Object object = methodProxy.invokeSuper(o, args);
                //调用方法之后,我们同样可以添加自己的操作
                System.out.println("after method " + method.getName());
                return object; // 方法的返回值,如果void则为null
            }
        };
        // 创建动态代理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(clazz);
        // 设置方法拦截器
        enhancer.setCallback(me);
        // 创建代理类
        return enhancer.create();
    }

    public static void main(String[] args) {
        MyDay myDay= (MyDay) CglibProxyFacory.getProxy(MyDay.class);
        myDay.work("早上8");
        myDay.sleep("晚上23");

    }

}

效果:

before method work
早上8点开始工作
after method work
before method sleep
晚上23点开始睡觉
after method sleep

1.5.2 cglib说明

主要要用到的3个类

这个就是拦截器处理接口,其重要接口方法


  /**
             * @param obj           被代理的对象(需要增强的对象)
             * @param method      被拦截的方法(需要增强的方法)
             * @param args        方法入参
             * @param proxy 用于调用原始方法
             * renturn  方法的返回值,如果void则为null
             */
   public Object intercept(
   Object obj, 
   java.lang.reflect.Method method,
   Object[] args,
   MethodProxy proxy
   ) throws Throwable;

这个方法为调用代理目标类的原始方法,其调用函数:MethodProxy.invokeSuperr(Object obj, Object[] args) ,其自动为代理目标类创建一个接口

/**
Object obj:传入代理目标类对象实例
 Object[] args:代理目标类的方法参数

**/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

这个类用于调用拦截器,创建增强的代理目标类

 		// 创建动态代理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(clazz);
        // 设置方法拦截器
        enhancer.setCallback(me);
        // 创建代理类-增强后的目标代理类
        Object obj=enhancer.create();

1.6 总结

反射机制:

  • 根据类的名称或者class本身,可以进行实例化对象、构造方法、获得和修改字段、获得方法名和调用方法

代理机制:

  • 代理机制就是代理本身目标类,增强其功能
  • 静态代理,就是继承目标类对应的接口,实现所有的接口方法,通过接口的封装,增强目标类
  • 动态代理:就是创造一个拦截器,拦截器里去增强目标类的方法,前提:必须有接口类
  • Cglib:增对目标类没有接口这种情况,自动创建一个接口,实现没有接口类也可以做代理

2. java小干货

2.1循环遍历

2.2可变参数

2.3 list和数组转化

2.4 地址引用

2.5集合

2.6文件流

2.7java代码块、内部类和匿名类

2.8 java泛型及通配符

2.9 日期类LocalDate

2.10枚举

2.11 java常见数据结构

3. java注解

4. lambda语言

5.http网络

6.java线程

12-24 20:45