常德市做网站联系电话/广东近期新闻
合成元素是存在于已编译的类文件中但不在其编译的源代码中的任何元素.通过检查元素是否为合成元素,可以区分这些元素,以便反射处理代码.这当然首先与使用反射的库相关,但它也与IDE等其他工具无关,这些工具不允许您调用合成方法或使用合成类.最后,Java编译器在编译期间验证代码永远不会直接使用合成元素也很重要.合成元素仅用于使Java运行时满意,它简单地处理(并验证)交付的代码,其中合成元素与任何其他元素相同.
您已经提到内部类作为Java编译器插入合成元素的示例,所以让我们看看这样一个类:
class Foo {
private String foo;
class Bar {
private Bar() { }
String bar() {
return foo;
}
}
Bar bar() {
return new Bar();
}
}
这个编译非常精细,但没有合成元素,它会被一个不了解内部类的JVM拒绝. Java编译器将上面的类看作如下所示:
class Foo {
private String foo;
String access$100() { // synthetic method
return foo;
}
Foo$Bar bar() {
return new Foo$Bar(this, (Foo$1)null);
}
Foo() { } // NON-synthetic, but implicit!
}
class Foo$Bar {
private final Foo $this; // synthetic field
private Foo$Bar(Foo $this) { // synthetic parameter
this.$this = $this;
}
Foo$Bar(Foo $this, Foo$1 unused) { // synthetic constructor
this($this);
}
String bar() {
return $this.access$100();
}
}
class Foo$1 { /*empty, no constructor */ } // synthetic class
如上所述,JVM不了解内部类,但强制成员的私有访问,即内部类无法访问其封闭类的私有属性.因此,Java编译器需要向被访问的类添加所谓的访问器,以便公开其不可见的属性:
> foo字段是私有的,因此只能从Foo中访问.访问$100方法将此字段公开给其包,其中始终找到内部类.此方法是合成的,因为它是由编译器添加的.
> Bar构造函数是私有的,因此只能从它自己的类中调用.为了实例化Bar的实例,另一个(合成)构造函数需要公开实例的构造.但是,构造函数具有固定的名称(在内部,它们都被称为< init>),因此我们不能将该技术应用于方法访问器,我们只是将它们命名为访问$xxx.相反,我们通过创建合成类型Foo $1来使构造函数访问器成为唯一的.
>为了访问其外部实例,内部类需要存储对此实例的引用,该引用存储在合成字段$this中.此引用需要通过构造函数中的合成参数传递给内部实例.
合成元素的其他示例是表示lambda表达式的类,使用类型发散签名覆盖方法时的桥接方法,创建由Maven构建或运行时代码生成器(如Byte Buddy)(无耻插件)等其他工具创建的Proxy类或类).