JDK 动态代理

Java 9 为何要将 String 的底层实现由 char[] 改成了 byte[]

Java 9将String底层实现从char[]改成byte[]的原因主要有以下几点:

  1. 节省内存空间:在Java 9之前,String的底层实现使用char[]来存储字符数据。每个char占用2个字节(16位),这意味着一个包含n个字符的字符串需要占用2n个字节的内存空间。而在Java 9中,String的底层实现改为使用byte[]来存储字符数据。对于ASCII字符(占1个字节),这种改变可以节省一半的内存空间。对于非ASCII字符,虽然仍然需要2个字节来表示,但在某些情况下,使用byte[]仍然可以节省内存空间。

  2. 提高性能:使用byte[]作为底层实现可以提高字符串操作的性能。因为byte[]数组的大小可以根据实际字符数据的需要动态调整,而不是固定为每个字符2个字节。这样可以减少内存分配和复制的次数,从而提高性能。

  3. 支持更多的字符集:Java 9引入了一种新的字符编码标准,即UTF-8。UTF-8是一种变长编码,可以使用1到4个字节来表示一个字符。通过使用byte[]作为底层实现,String可以更好地支持UTF-8编码,从而支持更多的字符集。

  4. 简化代码实现:在Java 9之前,String类的实现涉及到许多与char[]相关的复杂操作,例如字符数组的扩容、字符数组的复制等。通过将底层实现改为byte[],可以简化这些操作的实现,使代码更加简洁和易于维护。

总之,Java 9将String底层实现从char[]改成byte[]主要是为了节省内存空间、提高性能、支持更多的字符集以及简化代码实现。

String str="aaa"与 String str=new String(“aaa”)一样吗?new String(“aaa”);创建了几个字符串对象?

String str = "aaa"String str = new String("aaa") 在功能上是相同的,它们都创建了一个内容为 “aaa” 的字符串对象。但是,它们的创建方式和内存分配有所不同。

  1. String str = "aaa": 这种方式是通过字符串字面量创建字符串对象。Java编译器会在编译时将字符串字面量放入常量池(interned strings pool)中。当执行这行代码时,JVM会检查常量池中是否已经存在内容为 “aaa” 的字符串对象,如果存在,则直接引用该对象;如果不存在,则在常量池中创建一个新的字符串对象,并将其引用赋值给变量str。

  2. String str = new String("aaa"): 这种方式是通过new关键字创建字符串对象。首先,JVM会检查常量池中是否已经存在内容为 “aaa” 的字符串对象,如果存在,则在堆内存中创建一个新的字符串对象,并将其引用赋值给变量str;如果不存在,则在常量池中创建一个新的字符串对象,并在堆内存中再创建一个新的字符串对象,将其引用赋值给变量str。

关于 new String("aaa") 创建了几个字符串对象的问题:

  • 如果常量池中已经存在内容为 “aaa” 的字符串对象,那么只会在堆内存中创建一个新的字符串对象,总共创建了1个对象。
  • 如果常量池中不存在内容为 “aaa” 的字符串对象,那么会在常量池中创建一个字符串对象,并在堆内存中再创建一个新的字符串对象,总共创建了2个对象。

常量折叠

常量折叠是一种编译器优化技术,目的是减少运行时的计算开销

在Java中,常量折叠主要指的是编译期间对常量表达式的预处理和优化。具体来说,就是在编译阶段对程序中的某些常量表达式进行求值,将计算结果直接嵌入到生成的字节码中,从而避免了在程序运行时对这些表达式的重复计算。

例如,对于代码int a = 1 + 2;,经过常量折叠后,编译器会直接将其转换为int a = 3;。同样地,对于字符串字面量的相加操作,如String s1 = "a" + "b";,在编译期也会被优化为String s1 = "ab";。这样,在运行时就不需要再进行字符串连接操作,提高了代码的执行效率。

需要注意的是,常量折叠只适用于编译时常量,也就是那些在编译时就能确定其值的表达式。这包括数字字面量、字符串字面量以及被final修饰的字段。如果一个表达式中的变量或字段的值在编译时无法确定,那么这个表达式就无法进行常量折叠。

总的来说,常量折叠是提高程序运行效率的有效手段之一,它通过在编译阶段计算和简化表达式,减少了程序运行时的计算量和资源消耗。

代理模式

代理模式是一种常用的设计模式,它通过代理类来控制对被代理类的访问。在代理模式中,代理类和被代理类通常实现相同的接口,以便客户端可以无差别地使用它们。

以下是代理模式的一些关键点:

  1. 接口实现

    • 代理类(Proxy)和被代理类(RealSubject)都实现相同的接口(Subject)。这确保了客户端可以透明地使用代理对象,就像它是真正的对象一样。
  2. 引用持有

    • 代理类包含一个对被代理类对象的引用。这个引用可以在代理类的构造函数中通过参数传递,或者在运行时动态设置。
  3. 方法调用

    • 当客户端调用代理类的方法时,代理类可以在调用被代理类的实际方法之前或之后执行一些附加操作,如访问控制、日志记录、缓存处理等。
    • 根据代理的目的,代理类可以选择在某些情况下不调用被代理类的方法。例如,远程代理可能只在需要时才连接到远程服务器。
  4. 代理目的

    • 代理模式可以有不同的目的,包括但不限于:
      • 远程代理:为远程对象提供本地代理。
      • 虚拟代理:根据需要创建开销大的对象。
      • 安全代理:在调用实际方法前进行权限检查。
      • 智能引用:额外的逻辑,如引用计数、懒加载等。
      • 日志记录代理:记录方法调用的信息。
      • 防火墙代理:保护对象不被直接访问。
  5. 结构

    • 通常,代理模式的结构包括三个角色:
      • 抽象主题(Subject):定义真实主题和代理共同遵循的接口。
      • 真实主题(RealSubject):实现抽象主题的具体类,即被代理对象。
      • 代理(Proxy):含有对真实主题的引用,并可以在调用真实主题的方法前后添加其他行为。
  6. 客户端交互

    • 客户端通过代理接口与代理对象交云,不需要知道它正在与代理还是真实对象交云。这使得可以在不影响客户端代码的情况下切换或增加代理逻辑。
  7. 实现方式

    • 代理可以是静态的或动态的。静态代理通常手动编写,每个代理类对应一个被代理类。动态代理利用反射API在运行时动态生成代理类的字节码。
  8. 优点

    • 代理模式提供了一种灵活的方式来扩展或增强对象的功能,而无需修改原有对象的代码。
    • 它可以实现懒加载、访问控制、日志记录等功能,而不会影响到真实对象的业务逻辑。
  9. 缺点

    • 由于引入了代理层,可能会有一些性能开销。
    • 对于动态代理,可能需要处理额外的异常,如反射相关的异常。

在实际应用中,代理模式广泛应用于各种场景,如框架中的ORM代理、远程服务调用的代理、Spring框架的AOP代理等。通过代理模式,可以有效地分离关注点,提高系统的灵活性和可维护性。

JDK 动态代理

JDK动态代理是Java中的一种代理机制,它允许在运行时动态地创建一个代理对象,用于拦截和增强目标对象的方法调用。以下是对JDK动态代理的详细分析:

  1. 代理类的结构

    • JDK动态代理生成的代理类默认继承自java.lang.reflect.Proxy类。
    • 代理类实现了被代理类实现的所有接口。
    • 在代理类中重写了被代理类实现的接口方法,并在这些方法内部调用了InvocationHandlerinvoke方法。
  2. 代理对象的创建

    • 要创建代理对象,需要提供一个加载器(通常是当前线程的上下文加载器)、一个或多个接口(被代理类实现的接口)以及一个InvocationHandler实例。
    • 通过调用java.lang.reflect.Proxy类的静态方法newProxyInstance来创建代理对象。
  3. 方法调用的处理

    • 当客户端通过代理对象调用方法时,代理类会将调用请求委托给InvocationHandlerinvoke方法。
    • invoke方法接收到调用请求后,可以根据需要执行一些额外的逻辑,然后决定是否调用实际的目标方法。
  4. 局限性与限制

    • 由于Java是单继承的语言,JDK动态代理只能代理接口,不能代理类。这意味着被代理的对象必须是接口类型,不能是类类型。
    • 由于代理类是通过实现接口来工作的,因此无法直接代理被代理类的私有方法。私有方法通常不会被接口定义,因此代理类无法访问它们。
  5. 与CGLIB动态代理的比较

    • CGLIB动态代理是另一种代理机制,它不依赖于接口,而是通过继承被代理类来创建代理对象。
    • CGLIB动态代理可以代理类的方法,包括私有方法,因此在某些情况下可以解决JDK动态代理的局限性。
    • CGLIB动态代理的性能可能略低于JDK动态代理,因为它需要使用字节码操作来生成代理类。

总的来说,JDK动态代理是一种基于接口的代理机制,它可以在运行时动态地创建代理对象,并允许在方法调用前后执行额外的逻辑。然而,它的局限性在于只能代理接口,并且无法直接代理私有方法。相比之下,CGLIB动态代理提供了更灵活的代理能力,但可能会引入额外的性能开销。

CGLIB动态代理

CGLIB动态代理的工作原理

CGLIB(Code Generation Library)是一个强大的、高性能、高质量的Code生成类库,它广泛的被许多AOP框架使用,如Spring AOP和dynaop,为他们提供方法的拦截。

CGLIB动态代理的工作原理是通过继承被代理类来创建新的子类,在子类中实现对方法调用的拦截和增强。CGLIB通过使用一个字节码生成器来动态生成新的子类,这个子类实现了被代理类的所有方法,并提供了一个调用处理器(MethodInterceptor),用于在方法调用前后执行自定义的逻辑。

与Java原生代理(JDK Proxy)的区别
  1. 实现方式

    • JDK Proxy是基于接口的代理,要求被代理对象必须实现一个或多个接口。
    • CGLIB是基于类的继承来实现代理,不要求被代理对象实现接口,因此可以代理普通的类。
  2. 代理限制

    • JDK Proxy只能代理接口中声明的方法。
    • CGLIB可以代理类中所有的非final方法,包括私有方法。
  3. 性能

    • JDK Proxy通常有更好的性能,因为它直接利用了Java的反射机制。
    • CGLIB由于需要生成新的类,可能会有一些性能开销,但在最新版本中已经得到了优化。
  4. 使用场景

    • JDK Proxy适用于实现接口的目标对象。
    • CGLIB适用于没有实现接口或者需要代理非public方法的目标对象。
CGLIB动态代理的使用示例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGLIBProxyExample {public static void main(String[] args) {// 创建目标对象SomeClass target = new SomeClass();// 创建Enhancer对象Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method call: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("After method call: " + method.getName());return result;}});// 创建代理对象SomeClass proxy = (SomeClass) enhancer.create();// 调用代理对象的方法proxy.someMethod();}
}class SomeClass {public void someMethod() {System.out.println("Executing someMethod...");}
}
CGLIB动态代理的配置和使用场景

在Spring框架中,可以通过配置来选择使用CGLIB动态代理:

<bean id="someBean" class="com.example.SomeClass"><aop:scoped-proxy/>
</bean>

CGLIB动态代理适用于以下场景:

  • 当目标对象没有实现任何接口时,可以使用CGLIB动态代理。
  • 当需要代理目标对象的非public方法时,可以使用CGLIB动态代理。
  • 当需要在代理对象中添加额外的行为,例如日志记录、性能监控等,可以使用CGLIB动态代理。
常见问题及解决方法
  1. 性能问题

    • 尽量使用最新版本的CGLIB库,以获得更好的性能。
    • 如果可能,尽量使用JDK Proxy,因为它通常有更好的性能。
  2. 无法代理final方法

    • CGLIB无法代理final方法,因为final方法不能被子类覆盖。如果需要代理final方法,可以考虑使用其他AOP框架,如AspectJ。
  3. 版本兼容性问题

    • 确保使用的CGLIB版本与项目中的其他库兼容。如果有冲突,可以尝试升级或降级CGLIB版本。
CGLIB适用于没有实现接口或者需要代理非public方法的目标对象 为什么 public 不行

CGLIB 能够代理没有实现接口的目标对象,以及需要代理非 public 方法(包括 private、protected 和默认包访问权限的方法)的目标对象。对于 public 方法,使用 CGLIB 进行代理也是可行的,但关键在于 CGLIB 的代理机制提供了一种能力去代理那些在 JDK 动态代理中无法代理的方法。

在 CGLIB 中,当目标类没有实现任何接口时,或者你想代理的是类的非 public 方法时,CGLIB 通过生成目标类的子类来实现代理。这种代理方式允许你拦截并增强目标类的所有非 final 方法,无论这些方法是 public、protected、还是 private。

然而,对于 public 方法,如果你的目标类实现了一个或多个接口,并且你只想代理这些接口中定义的 public 方法,那么使用 JDK 动态代理通常是更好的选择,因为它更简单、性能也通常更好一些。JDK 动态代理只能代理接口中声明的方法,而不能代理类中新增的非接口方法。

总的来说,public 方法当然可以被 CGLIB 代理,但选择 CGLIB 来代理 public 方法通常是出于以下原因:

  1. 目标类没有实现任何接口:在这种情况下,JDK 动态代理无法使用,因此 CGLIB 是一个替代方案。
  2. 需要代理非 public 方法:CGLIB 可以代理非 public 方法,而 JDK 动态代理不能。
  3. 设计选择或习惯:有些开发者或团队可能会选择 CGLIB 作为所有代理需求的解决方案,以保持一致性。
  4. 高级用例:例如,当需要代理的方法调用涉及到复杂的逻辑判断,或者需要在代理实例创建前后执行一些特定逻辑时,CGLIB 提供的 MethodInterceptorCallbackFilter 等高级特性可能更加适合。

因此,说 CGLIB 适用于代理非 public 方法,并不是指它不能代理 public 方法,而是强调其独特的能力在于代理那些通常无法通过标准的 JDK 动态代理来处理的方法。

参考文章—JDK动态代理和CGLIB动态代理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/680058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法训练营】等式,道路升级(c++,python实现)

等式 问题描述 有n个变量和m个“相等”或“不相等”的约束条件&#xff0c;请你判定是否存在一种赋值方案满足所有m个约束条件。 输入格式 第一行一个整数T&#xff0c;表示数据组数。 接下来会有T组数据&#xff0c;对于每组数据&#xff1a; 第一行是两个整数n,m&#xff0c;…

Linux第52步_移植ST公司的linux内核第4步_关闭内核模块验证和log信息时间戳_编译_并通过tftp下载测试

1、采用程序配置关闭“内核模块验证” 默认配置文件“stm32mp1_atk_defconfig”路径为“arch/arm/configs”; 使用VSCode打开默认配置文件“stm32mp1_atk_defconfg”&#xff0c;然后将下面的4条语句屏蔽掉&#xff0c;如下&#xff1a; CONFIG_MODULE_SIGy CONFIG_MODULE_…

Json笔记

语法规则 数组&#xff08;Arrary&#xff09;&#xff1a;方括号&#xff3b;&#xff3d;对象&#xff08;Object&#xff09;&#xff1a;花括号{}名称/值对&#xff08;name/value&#xff09;&#xff1a;组合成数组和对象&#xff0c;之间用冒号隔开 名称置于双引号之中…

「数据结构」线性表

定义和基本操作 定义&#xff1a;相同数据类型的 n ( n ≥ 0 ) n(n \ge 0) n(n≥0)个数据元素的有限序列&#xff0c;其中n为表长&#xff0c;当n0时线性表是一个空表一般表示&#xff1a; L ( a 1 , a 2 , … … , a i , a i 1 , a n ) L(a_1,a_2,……,a_i,a_{i1},a_n) L(a…

【C语言】实现双向链表

目录 &#xff08;一&#xff09;头文件 &#xff08;二&#xff09; 功能实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;打印链表 &#xff08;3&#xff09; 头插与头删 &#xff08;4&#xff09;尾插与尾删 &#xff08;5&#xff09;指定位置之后…

STM32 + ESP8266,连接阿里云 上报/订阅数据

&#xff08;文章正在编辑中&#xff0c;一点点地截图操作过程&#xff0c;估计要拖拉两三天&#xff09; 一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是AT固件。连接阿里云&#xff0c;需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板&#xff0c;板载…

‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序

遇到 vue-cli-service 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 的错误时&#xff0c;通常意味着Vue CLI没有被正确安装或配置在项目中。这可能是因为node_modules目录缺失了必要的包&#xff0c;或者局部安装的Vue CLI没有被正确设置到系统的PATH环境…

洛谷: P1308 [NOIP2011 普及组] 统计单词数

前言: 这道题没理解清题目表达意思&#xff0c;我开始想的是用map来记录个数&#xff0c;然后一个变量记录一开始出现的单词位置&#xff0c;不挺简单的吗&#xff0c;然后....就AC了2个..从错误提示能看到个数没啥问题&#xff0c;但是第一个单词位置不对&#xff0c;看了新样…

二级C语言笔试10

(总分101,考试时间90分钟) 一、选择题 1. 设有如下关系表&#xff1a; A) TR∩S B) TR∪S C) TRS D) TR/S 2. 在一棵二叉树中&#xff0c;叶子结点共有30个&#xff0c;度为1的结点共有40个&#xff0c;则该二叉树中的总结点数共有( )个。 A) 89 …

【51单片机】AT24C02(江科大、爱上半导体)

一、AT24C02 1.AT24C02介绍 AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 存储介质:E2PROM 通讯接口:12C总线 容量:256字节 2.引脚即应用电路 本开发板AT24C02原理图 12C地址全接地,即全为0 WE接地,没有写使能 SCL接P21 S…

Microsoft Excel 加载数据分析工具

Microsoft Excel 加载数据分析工具 1. 打开 Excel&#xff0c;文件 -> 选项2. 加载项 -> 转到…3. 分析工具库、分析工具库 - VBA4. 打开 Excel&#xff0c;数据 -> 数据分析References 1. 打开 Excel&#xff0c;文件 -> 选项 2. 加载项 -> 转到… ​​​ 3…

不安全的 HTTP请求 漏洞原理以及修复方法

漏洞名称&#xff1a;不安全的HTTP方法、危险的HTTP方法 漏洞描述&#xff1a;不安全的HTTP方法一般包括&#xff1a;TRACE、PUT、DELETE、COPY 等。其中最常见的为TRACE方法可以回显服务器收到的请求&#xff0c;主要用于测试或诊断&#xff0c;恶意攻击者可以利用该方法进行…

【Java程序设计】【C00270】基于Springboot的moba类游戏攻略分享平台(有论文)

基于Springboot的moba类游戏攻略分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏攻略分享平台 本系统分为系统功能模块、管理员功能模块、以及用户后台功能模块。 系统功能模块&#xff1a;在平台首…

关闭Ubuntu 默认开启的自动安全更新

简介 Ubuntu 和 Debian 应该从很早版本开始预装unattended-upgrades 包&#xff0c;并开启自动更新有安全问题的软件包。 &#xff08;最小化安装不会安装此包&#xff09; 有什么影响&#xff1f; 如果软件包有安全漏洞&#xff0c;Ubuntu发布更新包后会自动安装更新并重启…

【开源】基于JAVA+Vue+SpringBoot的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

Ocr之TesseractOcr的安装及使用

目录 一、安装环境 二、安装内容 三、安装过程及识别测试 1. 安装过程 2. 程序编写 总结 1. 安装复杂度较低 2. 国外开源Ocr 3. 可设置识别参数 4. 工具类 一、 系统环境windows 10 linux环境也可安装, 可借鉴此篇文章>> | 二、安装内容 Tesseract exe 程序安…

常见的web前端开发框架:Vue.js

常见的Web前端开发框架包括Bootstrap、Vue.js、React.js、Angular.js等。每个框架都有其独特的特点和优势&#xff0c;开发者可以根据项目的需求和个人的喜好来选择合适的框架。同时&#xff0c;随着技术的不断发展&#xff0c;新的框架和工具也会不断涌现&#xff0c;为Web前端…

python学习23

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

数模.matlab符号计算方程

一、符号函数 a&#xff1a;整理简化&#xff1a; b&#xff1a;因式分解&#xff1a; c&#xff1a;多项式展开 d&#xff1a;合并&#xff1a; e&#xff1a;计算分子分母&#xff1a; f&#xff1a;求导&#xff1a; f&#xff1a;差分&#xff1a; g&#xff1a;不定积分&a…