java35-克隆-浅克隆-深克隆-java参数值传递-RMI-代理模式-静态代理-动态代理JDK-invocationHandler-newProxyInstance

本文主要是介绍java35-克隆-浅克隆-深克隆-java参数值传递-RMI-代理模式-静态代理-动态代理JDK-invocationHandler-newProxyInstance,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

时间
4/25

文章目录

      • 克隆
        • 概述
        • 实现克隆的方式
          • 实现Cloneable接口,并重写object类中的clone方法,可以实现浅克隆,也可以实现深克隆
          • 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的克隆
          • 利用BeanUtils,apache和spring都提供了bean工具,它是浅克隆
        • 浅克隆(Shallow Clone) 和 深克隆(Deep Clone)
          • 浅克隆(Shallow Clone)
          • 深克隆(Deep Clone)
        • 细节对比点
          • new操作符创建对象和clone方法复制对象的区别
          • 复制引用 和 复制对象 区别
          • 克隆两种实现方式的区别
      • java参数传递 = 值传递
      • RMI
      • Java中的动态代理
        • 代理模式
        • 静态代理
        • 动态代理
          • 基于接口的代理JDK
          • 基于继承的代理 CGlib

克隆

概述

克隆出现的原因:
在实际开发过程中,一个对象obj已经包含一些有用信息,这是我们需要将obj的信息复制到obj2中,使得obj和obj2对象具有两个完全不同的地址,修改一个对象的值,另一个对象不受影响。

实现克隆的方式
实现Cloneable接口,并重写object类中的clone方法,可以实现浅克隆,也可以实现深克隆
1 被克隆对象所属类必须实现Cloneable接口public class 类名 implements Cloneable{private 属性类 属性名;}
1-1 要想实现深克隆的话,类的成员属性 所在的类也需要实现Cloneable接口public class 属性类 implements Cloneable{}
2 所属类必须重写Object类的clone方法@Overridepublic Object clone() throws CloneNotSupportedException{类名 obj =(类名)super.clone(); // 浅克隆obj.属性名 = (属性类)属性名.clone(); //深克隆return obj;
}
实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的克隆
// 要序列化对象所属类 需要实现Serializable接口
public class 类名 implements Serializable{}
// 序列化
1 创建序列化流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件路径"));
2 创建对象类名 obj = new 类名();
3 使用序列化流的writeObject方法将对象写入指定的ObjectOutputStream流中oos.writeObject(obj);
4 释放资源oos.close();// 反序列化
1 创建反序列化流ObjectInputStream ois = new ObjectInputStream(new FileInputStream("文件路径"));
2 使用反序列化流的readObject方法从ObjectInputStream流中读取一个对象Object obj = ois.readObject();
3 强制转化对象类型类型 obj1 = (类型)obj;
4 释放资源ois.close();
利用BeanUtils,apache和spring都提供了bean工具,它是浅克隆

扩展

  • BeanUtils 是工具类,用于简化JavaBean的封装,简化数据的封装。(xhj理解:和collections是一样的,同样是工具类)
  • apache 是 世界使用排名第一的Web服务器软件,具有跨平台和安全性的优势,是最流行的Web服务器端软件之一。
  • Spring框架是一个开放源代码的J2EE应用程序框架,针对bean的生命周期进行管理的轻量级容器。
    在Spring中,构成应用程序主干并由Spring IOC容器管理的对象称为bean。bean是一个由Spring IOC容器实例化、组装和管理的对象。
    实例的创建不再由调用者管理,而是由Spring容器创建,容器会负责控制程序之间的关系,而不是由程序代码直接控制。
浅克隆(Shallow Clone) 和 深克隆(Deep Clone)

两种克隆方式主要区别在于是否支持引用类型的成员变量的复制。
java中的数据类型分为:基本数据类型(数值型{整型、浮点型、字符型}) 和 引用数据类型(接口、类、数组)

浅克隆(Shallow Clone)

浅克隆中,对象的复制只是复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
实现方法
覆盖Object类中的Clone()方法实现。

1 被复制的类需要实现Cloneable接口public class 类名 implements Cloneable{}
2 覆盖clone()方法,方法调用super.clone()方法得到需要的复制对象,输入clone有选项可以选择,自动生成。 修改为public访问级别@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}

实验分析:

1 被复制的类没有实现Cloneable接口,而直接使用  类名 对象2 = (类名)对象1.clone(); 会报错报clone()方法在java.lang.Object中是protected访问控制。
2 被复制的类实现Cloneable接口,使用 类名 对象2 = (类名)对象1.clone();  也会报错,需要抛出异常CloneNotSupportedException异常

案例:

// 320-test1
// 类
public class Student implements Cloneable{private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}// 测试类
public class StudentDemo {public static void main(String[] args) throws CloneNotSupportedException {Student s1 = new Student("汪苏泷",35);Student s2 = (Student)s1.clone();System.out.println(s1.getName() + ", " + s1.getAge());System.out.println("--------------");System.out.println(s2.getName() + ", " + s2.getAge());System.out.println(s1 == s2);// false 说明对象在堆内存中的地址不同}
}
深克隆(Deep Clone)

深克隆中,无论原型对象的成员变量的类型是值类型还是引用数据类型,都会复制一份给克隆对象。
实现方法:
方法一:通过覆盖Object类中的clone()方法实现

1 被复制对象的类 需要实现Cloneable接口,并重写Object类中的clone()方法。public class Outer implements Cloneable{private Inner inner;@Overridepublic Object clone() throws CloneNotSupportedException{Outer obj = (Outer)super.clone(); //类对象使用clone()方法obj.inner = (Inner)inner.clone();//类对象属性的类 使用clone()方法return obj;}}
2 Inner类也要实现Cloneable接口,重写Object类中的clone()方法。public class Inner implements Cloneable{@Overridepublic Object clone() throws CloneNotSupportedException{Inner obj = (Inner)super.clone();}
* 输入clone有选项可以选择 修改为public访问级别

方法二:使用序列化(Serialization)实现,序列化流ObjectOutputStream、反序列化流ObjectInputStream

// 序列化
1 创建序列化流对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("文件路径"));
2 创建对象类名 obj1 = new 类名();
3 使用序列化方法writeObject(Object obj)oos.writeObject(obj1);
4 释放资源oos.close();// 反序列化
1 创建反序列化对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("文件路径"));
2 使用反序列化方法readObject()Object obj = ois.readObject();
3 强制类型转换 Object =》 类名类名 obj2 =(类名)obj;
4 释放资源ois.close();

方法一案例:

// 320-test2
// Student的属性 的类
public class Address implements Cloneable {private String address;public Address() {}public Address(String address) {this.address = address;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}// Student 要克隆的对象所属的类
public class Student implements Cloneable{private String name;private int age;private Address addr;// 创建的是Address类的对象public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}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 Address getAddr() {return addr;}public void setAddr(Address addr) {this.addr = addr;}@Overridepublic Object clone() throws CloneNotSupportedException {Student stu = (Student)super.clone();//浅克隆stu.addr = (Address)addr.clone();//深克隆return stu;}
}
// 测试类
public class StudentDemo {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("西安市");Student s1 = new Student("汪苏泷",35);s1.setAddr(addr);Student s2 = (Student)s1.clone();System.out.println(s1.getName() + ", " + s1.getAge()+", "+s1.getAddr().getAddress());System.out.println(s2.getName() + ", " + s2.getAge()+", " + s2.getAddr().getAddress());
//        System.out.println(s1 == s2);// false 说明对象在堆内存中的地址不同// 修改前输出:   汪苏泷, 35, 西安市//              汪苏泷, 35, 西安市// 两个对象的Addr变量都一样,为了验证原对象和新对象是两个不一样的,这里对s2对象的Addr变量修改值addr.setAddress("重庆市");System.out.println("修改之后");System.out.println("--------------");System.out.println(s1.getName() + ", " + s1.getAge()+", "+s1.getAddr().getAddress());System.out.println(s2.getName() + ", " + s2.getAge()+", " + s2.getAddr().getAddress());// 对s2对象的成员变量addr进行修改,s1对象的addr变量也发生了变化。//  =》 说明 没有实现深克隆,只完成了浅克隆,成员是值类型的复制。// 要想实现深克隆,需要给Student类中的addr变量所处在类Address设置为浅克隆实现。// Address实现cloneable、且重写clone方法// 修改前输出:汪苏泷, 35, 重庆市//           汪苏泷, 35, 重庆市// 修改后输出:汪苏泷, 35, 重庆市//           汪苏泷, 35, 西安市}
}
细节对比点
new操作符创建对象和clone方法复制对象的区别
具体操作newclone
分配内存根据new操作符后面的类型分配对应大小的内存空间分配与源对象相同大小的内存空间
填充对象的域调用构造方法,填充对象的各个域(对象的初始化)使用源对象中对应的各个域填充新对象的域
对象创建完毕构造方法返回创建完毕的对象,并将其引用地址发布到外部(栈内存)clone()方法返回对象,并将其引用发布到外部(栈内存)
复制引用 和 复制对象 区别

A 是 源对象,B 是 新对象
复制引用 = A 和 B 地址值 相同,说明是一个对象
复制对象 = A 和 B 地址值 不相同,说明是两个对象

克隆两种实现方式的区别
区别项实现Cloneable接口的方式序列化和反序列化方式
是否可以实现深度克隆可以,
若对象属性嵌套很多引用类型,则需要在类中写多个.clone()方法,使用不是很方便
可以,使用方便
是否支持编译时检测异常不支持,是在运行时抛出异常的支持,通过泛型限定,可以检查出克隆的对象是否支持序列化,在编译阶段完成

java参数传递 = 值传递

当java传递的参数是基本数据类型时,一个方法不能改变基本数据类型参数的值;
当java传递的参数是引用数据类型时,一个方法可以修改引用数据类型参数所指向的对象的值;
值传递的精髓:传递的是存储单元中的内容,而不是存储单元的引用。

基本数据类型参数

// idea_face-test2-TransferTest
public class TransferTest {public static void main(String[] args) {int num = 1;System.out.println("method()方法调用前=" + num);method(num);System.out.println("method()方法调用后=" + num);}public static void method(int number){number = 2;}//method()方法调用前=1//method()方法调用后=1
}

分析:
在这里插入图片描述
引用数据类型参数

public class TransterTest2 {public static void main(String[] args) {Person p = new Person("汪苏泷");System.out.println("调用方法前= name:" + p.getName());method(p);System.out.println("调用方法后= name:" + p.getName());}public static void method(Person p){p.setName("许嵩");}// 调用方法前= name:汪苏泷// 调用方法后= name:许嵩
}

分析:
在这里插入图片描述

RMI

  • RMI(Remote Method Invocation),远程方法调用,允许运行在一个java虚拟机的对象调用运行在另一个java虚拟机上的对象的方法。两个虚拟机可以是运行在相同计算机上的不同进程,也可以是运行在网络中的不同计算机。
  • RPC(Remote Procedure Call),远程过程调用,用于一个进程调用另一个进程。

Java中的动态代理

代理模式
  • 代理模式(Proxy或Surrogate),就是一个人或机构代替另一个人或机构采取行动。
    一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
    代理就是为其他对象提供一个代理以控制对某个对象的访问。
  • 优点:
    可以隐藏真实目标类的实现;可以实现客户与真实目标类之间的解耦,在不修改真实目标类代码的情况下能够做一些操作;
  • 代理模式实现条件:
    代理类和被代理类实现共同的接口(或继承);
    代理类中存在指向被代理类的索引;( xhj 这个代理类的索引 = 创建的真实类的对象 )
    实际执行是通过调用代理类的方法从而实际执行被代理类的方法。
  • 代理分类:
    静态代理:程序员创建或特定工具自动生成源码,在对其进行编译。运行前,代理类的.class文件就已经存在了;
    动态代理:程序运行时,运用反射机制动态创建而成,动态代理类的字节码文件在程序运行时由java反射机制动态生成,无需程序员手工编写它的源代码。
    • 动态代理分类:
      基于接口的代理:代表 = JDK代理
      基于继承的代理:代表 = CGlib代理
静态代理

实现步骤

1 创建一个接口MyInterface,并创建抽象方法public interface MyInterface{// 创建抽象方法public abstract 返回值类型 method(接口MyInterface参数);}
2 创建MyInterface真实的实现类RealClass,重写接口中的抽象方法public class RealClass implements MyInterface{// 重写接口中的抽象方法,此时方法不在带有abstract修饰符@Overridepublic 返回值类型 method(接口MyInterface参数){真实的实现过程;}}
3 创建 代理类public class ProxyClass implements MyInterface{// 创建接口MyInterface的实现类对象,// 这里创建的是接口MyInterface的真实类对象,也就是代理类中指向被代理类的索引private MyInterface myinterface;// 创建带参构造方法(真实类 真实类对象)ProxyClass(MyInterface myinterface){this.myinterface = myinterface;}// 重写接口MyInterface中的抽象类方法@Overridepublic method(接口MyInterface参数){调用代理方法前做的事情;返回值 x = myinterface.method(接口MyInterface参数);调用代理方法后做的事情;}

理解

  • 好处:
    比如每次从磁盘中获取字体库的时候,磁盘的I/O比较耗时,想通过缓存将读到的字体库暂存一份,直接修改代理类ProxyClass,不用修改真实RealClass类。
    同样这样的需求直接修改RealClass类也可以实现,但是当多个RealClass2,RealClass3也需要判断缓存是否有字体的时候,那么修改真实类就需要修改多个,而采用代理类的形式,只需要修改一个类即可。

代码
需求:考虑一个字体提供功能,字体库可能源自本地磁盘、网络或者系统。

// 326-test1
// 接口
// 先考虑从本地磁盘中获取字体,采用代理的方式实现,定义一个提供字体的接口FontProvider:
public interface FontProvider {Font getFont(String name);
}
// 真实类:真正提供获取磁盘字体库的类
public class FontProviderFromDisk implements FontProvider{@Overridepublic Font getFont(String name) {System.out.println("磁盘上的字体库");return null;}// 只是输出文字,返回值类型可以不写为Font类型,而是写为void
}
// 代理类
public class ProxyForFont implements FontProvider{private FontProvider fontProvider;// 定义一个接口对象,实际上是被代理类对象ProxyForFont(FontProvider fontProvider){this.fontProvider = fontProvider;}// 定义带参构造方法,参数为接口对象@Overridepublic Font getFont(String name) {System.out.println("提供代理方法前做的事情");Font font = fontProvider.getFont(name);System.out.println("调用代理后做的事情");return font;}
}
// 测试类
public class MyFontDemo {public static void main(String[] args) {FontProvider fp = new ProxyForFont(new FontProviderFromDisk());// 多态的形式创建FontProvider接口对象// 接口 对象名 = new 代理类名(new 真实类名());fp.getFont("宋体");}
}
动态代理

出现的原因
当需要获取多种资源,比如字体、图片、音乐等资源,这时就需要多个接口,比如FontProvider、ImageProvider、MusicProvider接口等,需要对应的实现类(比如FontClass、ImageClass、MusicClass等),和其对一个的代理类(比如FontProxy、ImageProxy、MusicProxy等)。当需要给获取字体、图片、音乐等功能上加上缓存功能,就需要对三个代理类进行改动,但是修改的部分逻辑上又相同,就会造成代码的重复和代理类爆炸。
分类: 基于接口的代理(JDK) 和 基于继承的代理(CGlib)

基于接口的代理JDK

InvocationHandler接口

  • InvocationHandler接口
    每个代理类的实例都会有一个与之相关联的InvocationHandler实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
public interface InvocationHandler { // 接口// 唯一的方法invokepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

参数介绍:

参数名说明
Object proxy代理对象
Method method代理对象调用的方法
Object[] args调用方法中的参数

Proxy类的静态newProxyInstance方法
返回指定接口的代理实例,该代理实例将方法调用分配给指定的调用处理程序。

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

参数介绍:

参数名说明获得
ClassLoader loader类加载器测试类.class.getClassLoader()
Class<?>[] interfaces用来代理的接口new Class[]{接口.class}
也就是说这里可以是多个接口.class
InvocationHandler h一个InvocationHandler对象InvocationHandler handler = new jdkProxyClass(new RealSubject());
jdkProxyClass是代理类,RealSubject是真实类

说明

  • 测试类.class.getClassLoader()
    测试类.class,得到该类对应的Class类对象,通过类的class属性
    Class类对象.getClassLoader(),得到Class类对象的类加载器
  • Class<?>[] interfaces = new Class[]{接口.class}
    2022/4/25 理解:需要创建一个Class数组,成员是接口的Class对象。

具体的实现步骤

1 创建接口MyInterfacepublic interface MyInterface{// 定义抽象方法public abstract 返回值类型 method1();public abstract 返回值类型 method2();}2 创建真实的接口实现类RealClasspublic class RealClass{// 重写抽象方法@Overridepublic 返回值类型 method1(){method1具体的实现;}@Overridepublic 返回值类型 method2(){method2具体的实现;}}3 创建接口的代理类,需要实现InvocationHandler接口public class jdkProxyClass implements InvocationHandler{// 创建接口的真实类对象private RealClass realObj;// 创建真实类对象为参数的带参构造方法public jdkProxyClass(RealClass realObj){this.realObj = realObj;}// 重写Object类中的invoke方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// proxy 被代理的对象;method:调用的方法;args:方法所需的参数执行代理调用之前的操作。Object result = null;// 这里的方法是通过反射获取的方法对象result = method.invoke(realObj,args);return result;}4 创建测试类public class jdkDemo{public static void main(String[] args){// 创建要代理的真实对象,采用多态的形式MyInterface realObj = new RealClass();// 创建代理对象InvocationHandler handler = new jdkProxyClass(realObj);// 使用Proxy.newProxyInstrace()这个静态方法 获得接口的对象MyInterface myinterface = (MyInterface)Proxy.newProxyInstance(jdkDemo.class.getClassLoader(),new Class[]{MyInterface.class},handler);// 通过接口对象调用方法myinterface.method1();myinterface.method2();}

案例:

// 326-test2
// 接口定义
public interface Subject {void method1();void method2();
}
// 接口真实的实现类定义
public class RealSubject implements Subject{@Overridepublic void method1() {System.out.println("method1执行");}@Overridepublic void method2() {System.out.println("method2执行");}
}// 接口的代理类定义
public class jdkProxySubject implements InvocationHandler {// 创建代理类的真实对象,也就是真实类的对象private Object subject;// 创建带参构造方法public jdkProxySubject(Object subject){this.subject = subject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// proxy:被代理的对象// method:调用的方法// args:方法所需要的参数System.out.println("before");Object result = null;try{// 利用反射动态的来反射方法,动态代理和静态代理的区别result = method.invoke(subject, args);}catch(Exception e){System.out.println("ex:" + e.getMessage());}finally {System.out.println("after");}return result;}
}
// 测试类
public class Client {public static void main(String[] args){// 创建要代理的真实对象Subject realSubject = new RealSubject();// 创建代理对象,将真实对象作为参数传入InvocationHandler handler =new jdkProxySubject(realSubject);Subject subject = (Subject)Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{Subject.class}, handler);subject.method1();subject.method2();}
}
基于继承的代理 CGlib

概述

  • CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,为一个类创建子类,并在子类中采用方法拦截技术 拦截所有对父类方法的调用,并顺势加入横切逻辑。
    ASM是一款java字节码层面的代码分析和修改工具。
    ASM的目标是生成、转换、分析已编译的java class文件,可使用ASM工具读/写/转换JVM指令集。
  • CGlib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理,因为采用的是继承,所以不能对final修饰的类进行代理。
    由于spring框架中的MethodInterceptor接口,目前没有学习spring框架 ,后期总结。
    参考博客

这篇关于java35-克隆-浅克隆-深克隆-java参数值传递-RMI-代理模式-静态代理-动态代理JDK-invocationHandler-newProxyInstance的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/693468

相关文章

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

Spring Boot中的路径变量示例详解

《SpringBoot中的路径变量示例详解》SpringBoot中PathVariable通过@PathVariable注解实现URL参数与方法参数绑定,支持多参数接收、类型转换、可选参数、默认值及... 目录一. 基本用法与参数映射1.路径定义2.参数绑定&nhttp://www.chinasem.cnbs

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

Java中Integer128陷阱

《Java中Integer128陷阱》本文主要介绍了Java中Integer与int的区别及装箱拆箱机制,重点指出-128至127范围内的Integer值会复用缓存对象,导致==比较结果为true,下... 目录一、Integer和int的联系1.1 Integer和int的区别1.2 Integer和in

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.