slf4j 桥接与被桥接_合成和桥接方法
slf4j 桥接与被桥接
如果您曾经玩过反射并执行了getDeclaredMethods()
您可能会感到惊讶。 您可能会获得源代码中不存在的方法。 或者,也许您看了一些方法的修饰符,发现其中一些特殊方法是易变的。 顺便说一句:对于Java采访来说,这是一个令人讨厌的问题,“当方法易变时,这意味着什么?” 正确的答案是方法不能是易变的。 同时,在getDeclaredMethods()
甚至getMethods()
返回的方法中可能存在某些方法,对于这些方法, Modifier.isVolatile(method.getModifiers())
为true。
这是项目转换器的用户之一发生的 。 他意识到,交换器(本身会深入挖掘Java的黑暗细节)生成的Java源代码无法使用关键字volatile
作为方法的修饰符进行编译。 结果,它也不起作用。
那里发生了什么事? 桥接和合成方法是什么?
能见度
创建嵌套或嵌入式类时,可以从顶级类访问嵌套类的私有变量和方法。 这由不可变的嵌入式构建器模式使用 。 这是语言规范中定义的Java的明确定义的行为。
JLS7,6.6.1确定可访问性
…如果成员或构造函数被声明为私有,则访问为
当且仅当它出现在顶级类的主体中时才允许(第7.6节)
包含成员或构造函数的声明…
package synthetic;public class SyntheticMethodTest1 {private A aObj = new A();public class A {private int i;}private class B {private int i = aObj.i;}public static void main(String[] args) {SyntheticMethodTest1 me = new SyntheticMethodTest1();me.aObj.i = 1;B bObj = me.new B();System.out.println(bObj.i);}
}
JVM如何处理它? JVM不知道内部或嵌套类。 对于JVM,所有类都是顶级外部类。 所有类都被编译为顶级类,这就是那些不错的方法...$. .class
...$. .class
文件已创建。
$ ls -Fart
../ SyntheticMethodTest2$A.class MyClass.java SyntheticMethodTest4.java SyntheticMethodTest2.java
SyntheticMethodTest2.class SyntheticMethodTest3.java ./ MyClassSon.java SyntheticMethodTest1.java
如果创建嵌套或内部类,它将被编译为完整的顶级类。
外层如何提供私有字段? 如果这些人进入了真正的顶级阶层并且是私人的,那么他们如何从外部阶层得到呢?
javac解决此问题的方式是,对于任何私有字段但从顶级类使用的字段,方法或构造函数,它都会生成综合方法。 这些合成方法用于到达原始私有字段/方法/构造函数。 这些方法的生成以巧妙的方式完成:仅生成真正需要并从外部使用的那些方法。
package synthetic;import java.lang.reflect.Constructor;
import java.lang.reflect.Method;public class SyntheticMethodTest2 {public static class A {private A(){}private int x;private void x(){};}public static void main(String[] args) {A a = new A();a.x = 2;a.x();System.out.println(a.x);for (Method m : A.class.getDeclaredMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " " + m.getName());}System.out.println("--------------------------");for (Method m : A.class.getMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());}System.out.println("--------------------------");for( Constructor<?> c : A.class.getDeclaredConstructors() ){System.out.println(String.format("%08X", c.getModifiers()) + " " + c.getName());}}
}
由于生成的方法的名称取决于实现方式,因此不能保证对上述程序的输出最多的是,在我执行该程序的特定平台上,它会产生以下输出:
2
00001008 access$1
00001008 access$2
00001008 access$3
00000002 x
--------------------------
00000111 void wait
00000011 void wait
00000011 void wait
00000001 boolean equals
00000001 String toString
00000101 int hashCode
00000111 Class getClass
00000111 void notify
00000111 void notifyAll
--------------------------
00000002 synthetic.SyntheticMethodTest2$A
00001000 synthetic.SyntheticMethodTest2$A
在上面的程序中,我们为字段x
赋值,并且还调用了相同名称的方法。 这些是触发编译器生成综合方法所必需的。 您可以看到它生成了三种方法,大概是字段x
的setter和getter以及方法x()
的综合方法。 但是,这些综合方法未在getMethods()
返回的下一个列表中列出,因为它们是综合方法,因此不适用于通用调用。 从这个意义上讲,它们是私有方法。
十六进制数字可以用作解释器,查看类java.lang.reflect.Modifier
定义的常量:
00001008 SYNTHETIC|STATIC
00000002 PRIVATE
00000111 NATIVE|FINAL|PUBLIC
00000011 FINAL|PUBLIC
00000001 PUBLIC
00001000 SYNTHETIC
列表中有两个构造函数。 有一个私人的和一个合成的。 私有存在,因为我们定义了它。 另一方面,合成的存在是因为我们从外部调用了私有的。 到目前为止,桥接方法还没有。
泛型和继承
到目前为止,还不错,但是我们仍然没有看到任何“易变”的方法。
查看java.lang.reflec.Modifier
的源代码,您可以看到常量0x00000040
被定义了两次。 一次是VOLATILE
,一次是BRIDGE
(后者是私有程序包,不用于一般用途)。
要拥有这样一种方法,一个非常简单的程序就可以做到:
package synthetic;import java.lang.reflect.Method;
import java.util.LinkedList;public class SyntheticMethodTest3 {public static class MyLink extends LinkedList<String> {@Overridepublic String get(int i) {return "";}}public static void main(String[] args) {for (Method m : MyLink.class.getDeclaredMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());}}
}
我们有一个链表,该链表的方法get(int)
返回String
。 我们不要讨论干净的代码问题。 这是演示该主题的示例代码。 干净的代码中也会出现同样的问题,尽管更复杂,更难在出现问题时解决。
输出显示:
00000001 String get
00001041 Object get
我们有两个get()
方法。 一个出现在源代码中,另一个出现在源代码中并且是合成的。 反编译器javap
表示生成的代码是:
public java.lang.String get(int);Code:Stack=1, Locals=2, Args_size=20: ldc #2; //String2: areturnLineNumberTable:line 12: 0public java.lang.Object get(int);Code:Stack=2, Locals=2, Args_size=20: aload_01: iload_12: invokevirtual #3; //Method get:(I)Ljava/lang/String;5: areturn
有趣的是,这两种方法的签名是相同的,只是返回类型不同。 JVM允许这样做,即使Java语言无法做到这一点。 bridge方法不执行其他任何操作,而是调用原始方法。
为什么需要这种合成方法? 谁来使用它。 例如,想要使用类型MyLink
的变量来调用方法get(int)
的MyLink
:
List<?> a = new MyLink();Object z = a.get(0);
它不能调用返回String
的方法,因为List
没有这样的方法。 为了使其更具说明性,让我们重写方法add()
而不是get()
:
package synthetic;import java.util.LinkedList;
import java.util.List;public class SyntheticMethodTest4 {public static class MyLink extends LinkedList<String> {@Overridepublic boolean add(String s) {return true;}}public static void main(String[] args) {List a = new MyLink();a.add("");a.add(13);}
}
我们可以看到桥接方法
public boolean add(java.lang.Object);Code:Stack=2, Locals=2, Args_size=20: aload_01: aload_12: checkcast #2; //class java/lang/String5: invokevirtual #3; //Method add:(Ljava/lang/String;)Z8: ireturn
不仅叫原版。 它还检查类型转换是否正确。 这是在运行时完成的,而不是由JVM本身完成的。 如您所料,它确实出现在第18行中:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stringat synthetic.SyntheticMethodTest4$MyLink.add(SyntheticMethodTest4.java:1)at synthetic.SyntheticMethodTest4.main(SyntheticMethodTest4.java:18)
下次在面试中遇到关于不稳定方法的问题时,您可能比面试官了解的更多。
翻译自: https://www.javacodegeeks.com/2014/03/synthetic-and-bridge-methods.html
slf4j 桥接与被桥接
slf4j 桥接与被桥接_合成和桥接方法相关推荐
- 桥接路由器总是掉线_多路由的无线桥接步骤
网络现在已经是我们生活中不可或缺的一部分了,尤其是更方便我们使用的WIFI.使用手机连接WIFI摆脱了线缆的束缚,我们可以走着看,坐着看,躺着看,在客厅看,在厨房看,在卧室看,甚至还能在厕所看,变化各 ...
- 桥接路由器总是掉线_无线路由器桥接完整教程(不会断网)【图文详解】
无线路由器桥接完整教程(不会断网) [图文详解] 路由器桥接是很实用的功能,但网上很多方法不完整,导致路由器桥接是成功了 , 但副路 由经常断网.原因呢?网上很多教程都有这一步 : 在设置副路由( B ...
- 路由器mw320虚拟服务器,水星MW320R中继怎么设置_水星MW320R桥接设置-192路由网
本文主要介绍了水星MW320R路由器的中继(桥接)设置教程,也就是用水星MW320R路由器,来放大原来路由器的无线信号,实现扩大无线信号覆盖范围的目的. 水星MW320R无线路由器,要桥接原来路由器的 ...
- 桥接模式解密:跨越鸿沟,桥接抽象与实现
快捷导航 一.概要 1.1 优点 1.2 缺点 1.3 适用场景 二.模拟支付场景 三.总结 一.概要 桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们 ...
- 04jquery事件_合成事件hover()使用
04jquery事件_合成事件hover(事件切换hover(鼠标移上来, 鼠标移下去)) 方法解析 代码 hover(over, out) $("td").hover( func ...
- numpy序列预处理dna序列_合成生物学快讯2019年第12期:基于DNA的分子数字数据存储...
本文由中国科学院上海生命科学信息中心 战略情报团队供稿 基于DNA的分子数字数据存储:现状与挑战 编者按:美国华盛顿大学和微软研究院的研究人员2019年8月在Nature杂志发文,对基于DNA的分子数 ...
- Slf4j与log4j及log4j2的关系及使用方法
Slf4j与log4j及log4j2的关系及使用方法 slf4j slf4j仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已,所以单独 ...
- ChinaSoft 论坛巡礼 | 软件智能合成理论与方法
2022年CCF中国软件大会(CCF ChinaSoft 2022)将于2022年11月25-27日在上海国际会议中心举行.预期将有林惠民.陈左宁.邬江兴.何积丰.梅宏.吕建.柴洪峰.王怀民.郑纬民. ...
- 2022 CCF中国软件大会(CCF Chinasoft)“软件智能合成理论与方法”论坛成功召开...
2022年11月25日,2022 CCF中国软件大会(CCF Chinasoft)软件智能合成理论与方法论坛成功举办.本次论坛由中国科学院软件所詹乃军研究员.北京大学李戈教授.西北工业大学沈博副教授及 ...
最新文章
- MariaDB 10.0 和 MySQL 5.6 有何不同
- stringstream用法总结
- Spring 学习笔记(二)Spring AOP
- .NET Core开发日志——Middleware
- Application对象 简单的聊天室
- Android CardView的基本使用
- 初创公司 经营_LibreCorps指导人道主义初创公司如何运行开源方式
- mysql记录是乱码_mysql查询数据库导致中文乱码
- Ext自定义控件 - 自学ExtJS
- AcWing 893. 集合-Nim游戏(SG函数)
- mysql查询时间段内数据
- 计算机三本院校大学排名,全国三本大学排名
- SAP中物料成本视图原始组的应用原理分析
- 翻译 RFC 7322: RFC 样式指南
- Android Studio Menu item 的简单使用
- 初生牛犊不怕虎,管他呢! 干就是了。
- h5跳转微信公众号文章,小程序,任意站跳转链接制作方法?
- 【LeeCode】赛题02:Python解答大衍数列题目
- The Places of Our Lives: Visiting Patterns and Automatic Labeling from Longitudinal Smartphone Data
- 如何给码农的Mac开光