首先我们应该达成一个共识:很多的Java语法糖都是编译器赋予的,而JVM是一个与Java语言解耦的平台。有了这个共识,再来看今天的主角:synthetic修饰符。
我们在阅读JDK反射包源码时,会遇到isSynthetic()方法,其实现之一是Modifier.isSynthetic(getModifiers()),其他实现方式的原理一样。Modifier是专门定义修饰符的类,其中static final int SYNTHETIC = 0x00001000 表明synthetic是修饰符的一种。
我尝试用synthetic来修饰自定义的Class/Field/Method/Constructer。但是都会编译失败,理由是不认识synthetic修饰符。那么synthetic到底是怎么使用的呢?
官方定义
我从Java语言规范中找到了定义:
Any constructs introduced by the compiler that do not have a corresponding construct in the source code must be marked as synthetic ,except for default constructs and the class initialization method.
意思大概是这样:任何被编译器引入的构造器在源代码中没有一个相应的构造器,那么该段代码就必须要被标记为synthetic的(复合的),除了默认的构造器和类初始化方法。
验证
基于上面的定义,我们知道synthetic是由编译器生成的,而且synthetic有复合的、合成的意思。所以猜测是否是用在内部类中的。我们先构造一个内部类:
public class SyntheticDemo {
public static void main(String[] args) {
InnerClass innerObject = new InnerClass();
System.out.println("inner: " + innerObject.inner);
}
private static class InnerClass{
private String inner = "我在内部";
}
}
编译后生成了三个文件:
- SyntheticDemo$1.class
- SyntheticDemo$InnerClass.class
- SyntheticDemo.class
我们依次反编译一下这三个class文件
SyntheticDemo$1.class
javap SyntheticDemo$1.class:
Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$1 {
}
javap -v SyntheticDemo$1.class
Last modified 2019-12-12; size 205 bytes
MD5 checksum 942560dec8fdbc3d9b65e31e4b41295a
Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$1
minor version: 0
major version: 52
flags: ACC_SUPER, ACC_SYNTHETIC
Constant pool:
#1 = Class #7 // compiler/SyntheticDemo$1
#2 = Class #9 // java/lang/Object
#3 = Utf8 SourceFile
#4 = Utf8 SyntheticDemo.java
#5 = Utf8 EnclosingMethod
#6 = Class #10 // compiler/SyntheticDemo
#7 = Utf8 compiler/SyntheticDemo$1
#8 = Utf8 InnerClasses
#9 = Utf8 java/lang/Object
#10 = Utf8 compiler/SyntheticDemo
{
}
SourceFile: "SyntheticDemo.java"
EnclosingMethod: #6.#0 // compiler.SyntheticDemo
InnerClasses:
static #1; //class compiler/SyntheticDemo$1
这个类里面什么都没有,并且此类的flags包含ACC_SYNTHETIC。
SyntheticDemo$InnerClass.class
javap SyntheticDemo$InnerClass.class:
Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$InnerClass {
compiler.SyntheticDemo$InnerClass(compiler.SyntheticDemo$1);
static java.lang.String access$100(compiler.SyntheticDemo$InnerClass);
}
javap SyntheticDemo$InnerClass.class:
Classfile /D:/idea_workspace/mycode/target/classes/compiler/SyntheticDemo$InnerClass.class
Last modified 2019-12-12; size 763 bytes
MD5 checksum f13a4310236918575d26a2909aa8507e
Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$InnerClass
minor version: 0
major version: 52
flags: ACC_SUPER
Constant pool:
#1 = Fieldref #5.#26 // compiler/SyntheticDemo$InnerClass.inner:Ljava/lang/String;
#2 = Methodref #5.#27 // compiler/SyntheticDemo$InnerClass."<init>":()V
#3 = Methodref #6.#27 // java/lang/Object."<init>":()V
#4 = String #28 // 我在内部
#5 = Class #30 // compiler/SyntheticDemo$InnerClass
#6 = Class #31 // java/lang/Object
#7 = Utf8 inner
#8 = Utf8 Ljava/lang/String;
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 LocalVariableTable
#14 = Utf8 this
#15 = Utf8 InnerClass
#16 = Utf8 InnerClasses
#17 = Utf8 Lcompiler/SyntheticDemo$InnerClass;
#18 = Class #32 // compiler/SyntheticDemo$1
#19 = Utf8 (Lcompiler/SyntheticDemo$1;)V
#20 = Utf8 x0
#21 = Utf8 Lcompiler/SyntheticDemo$1;
#22 = Utf8 access$100
#23 = Utf8 (Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
#24 = Utf8 SourceFile
#25