1. 首页
  2. IT资讯

Java 中冷门的 synthetic 关键字原理解读

“u003Cdivu003Eu003Cpu003E看JAVA的反射时,看到有个synthetic ,还有一个方法isSynthetic() 很好奇,就了解了一下:u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E1.定义u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003EAny constructs introduced by a Java compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors, the class initialization method, and the values and valueOf methods of the Enum class.u003Cu002Fpu003Eu003Cpu003E大意为:由java编译器生成的(除了像默认构造函数这一类的)方法,或者类u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E2.实例u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E既然知道synthetic方法和synthetic类是由编译器生成的,那到底编译器会怎么生成这些东西,又在什么情况下会生成这些东西呢?u003Cu002Fpu003Eu003Cpu003E先看一段代码:u003Cu002Fpu003Eu003Cpreu003Eimport static java.lang.System.out;u003Cbru003Epublic final class DemonstrateSyntheticMethodsu003Cbru003E{u003Cbru003E public static void main(final String[] arguments)u003Cbru003E {u003Cbru003E DemonstrateSyntheticMethods.NestedClass nested =u003Cbru003E new DemonstrateSyntheticMethods.NestedClass();u003Cbru003E out.println(“String: ” + nested.highlyConfidential);u003Cbru003E }u003Cbru003E private static final class NestedClassu003Cbru003E {u003Cbru003E private String highlyConfidential = “Don’t tell anyone about me”;u003Cbru003E private int highlyConfidentialInt = 42;u003Cbru003E private Calendar highlyConfidentialCalendar = Calendar.getInstance();u003Cbru003E private boolean highlyConfidentialBoolean = true;u003Cbru003E }u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E编译之后,可以看到三个文件:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002Fa33ccca180fa4702848a15d43e2ae459″ img_width=”360″ img_height=”74″ alt=”Java 中冷门的 synthetic 关键字原理解读” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E其中,最下面的这个类文件很好解释,就是我们的主class,中间的文件,是我们的内部类,上面的文件,后面再讲,我们先看一下中间这个内部类u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E2.1 内部类的反编译结果u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E用javap 反编译DemonstrateSyntheticMethods$NestedClass.class,得到如下结果:u003Cu002Fpu003Eu003Cpreu003Ejavap DemonstrateSyntheticMethods\$NestedClass.classu003Cbru003ECompiled from “DemonstrateSyntheticMethods.java”u003Cbru003Efinal class DemonstrateSyntheticMethods$NestedClass {u003Cbru003E DemonstrateSyntheticMethods$NestedClass(DemonstrateSyntheticMethods$1);u003Cbru003E static java.lang.String access$100(DemonstrateSyntheticMethods$NestedClass);u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E先把构造函数放一边,我们来看这个标黑的方法access$100 这个是怎么回事呢?我们的源文件里找不到这个access方法啊?u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E2.2 synthetic方法u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E这个方法就是编译器生成的synthetic方法,读者不信的话,可以用method.isSynthetic() 去验证一下。u003Cu002Fpu003Eu003Cpu003E为何要生成这样一个方法呢?u003Cu002Fpu003Eu003Cpu003E可以看到,我们的NestedClass类中,highConfidential是一个私有属性,而我们在外部类DemonstrateSyntheticMethods中,直接引用了这个属性。作为一个内部类,NestedClass的属性被外部类引用,在语义上毫无问题,但是这却苦了编译器。u003Cu002Fpu003Eu003Cpu003E为了能让一个private的变量被引用到,编译器生成了一个package scope的access方法,这个方法就是一个get方法,在外部类使用highConfidential这个属性时,实际是使用了这个access方法。u003Cu002Fpu003Eu003Cpu003E在javap中可以看到直接的证据:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002Fd5b45681bbd74d2093adb1ad622e37b0″ img_width=”893″ img_height=”430″ alt=”Java 中冷门的 synthetic 关键字原理解读” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E图中红框的位置,可以很清楚的看到main方法实际上调用了access$100这个方法。u003Cu002Fpu003Eu003Cpu003E所以,结论很清楚了,编译器为了方便内部类的私有成员被外部类引用,生成了一个get方法,这可以被理解为一个trick,绕开了private成员变量的限制。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E2.3 synthetic类u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E定义已经提到,编译器不仅仅会生成方法,也会生成synthetic类。u003Cu002Fpu003Eu003Cpu003E我们回过头来看2.1提到的最后一个类DemonstrateSyntheticMethods$1.classu003Cu002Fpu003Eu003Cpu003E这个类是一个完全的空类,反编译后是这个样子:u003Cu002Fpu003Eu003Cpreu003Eu002Fu002F $FF: synthetic classu003Cbru003Eclass DemonstrateSyntheticMethods$1 {u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E这个类只出场了一次,作为内部类NestedClass的package scope的构造函数,如图所示:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F0c4b9b01a0f949bfa4917062ee9955bb” img_width=”851″ img_height=”225″ alt=”Java 中冷门的 synthetic 关键字原理解读” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E那么,这个类的作用呢?笔者查了很多资料,都没有明确的说明这个类的用途,只能根据代码做推测如下:u003Cu002Fpu003Eu003Cpu003ENestedClass作为一个private类,其默认构造函数也是private的。那么,事实上,作为外部类的DemonstrateSyntheticMethods类,没有办法new这个内部类的对象,而这和我们需要的语义相违背。u003Cu002Fpu003Eu003Cpu003E那么,为了实现语义,编译器又用了一个trick,悄悄的生成了一个构造函数NestedClass(DemonstrateSyntheticMethods$1 obj), 这个构造函数是包可见的。u003Cu002Fpu003Eu003Cpu003E那么,外部类则可以通过new NestedClass(null)的方式,得到内部类的对象。如果读者检查一下main方法的话,可以看到这个方法的调用如下图所示。u003Cu002Fpu003Eu003Cpu003E这就是这个synthetic类的作用。如果我们给我们的NestedClass 增加一个public级别的默认构造函数的话,则可以看到编译器不会再生成这个synthetic类。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002Ff43c318d7b934d59b9691700ab8022bf” img_width=”1053″ img_height=”470″ alt=”Java 中冷门的 synthetic 关键字原理解读” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003Eu003Cstrongu003E3.结论u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E编译器通过生成一些在源代码中不存在的synthetic方法和类的方式,实现了对private级别的字段和类的访问,从而绕开了语言限制,这可以算是一种trick。u003Cu002Fpu003Eu003Cpu003E在实际生产和应用中,基本不存在程序员需要考虑synthetic的地方。u003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:Java 中冷门的 synthetic 关键字原理解读

主题测试文章,只做测试使用。发布者:逗乐男神i,转转请注明出处:http://www.cxybcw.com/26498.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code