Java 中的合成类

什么是 Java 中的合成类? 为什么要使用它? 我如何使用它?

59578 次浏览

我在谷歌上找到了第一个问题的答案:

如果下列情况下,类可以标记为合成的 它是由编译器生成的,即 是,它不出现在源 密码。

这只是一个基本的定义,但我发现它在一个论坛帖子,没有解释。还在找更好的..。

Java 具有在运行时创建类的能力。这些类被称为合成类或动态代理。

有关更多信息,请参见 http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html

其他开源库,如 CGLIBASM也允许您生成合成类,并且比 JRE 提供的库更强大。

合成类由 AOP (面向方面编程)库(如 Spring AOP 和 AspectJ)以及 ORM 库(如 Hibernate)使用。

EasyMock 还使用合成类或动态代理在运行时创建接口或抽象类的实现。

Http://www.easymock.org/

根据 这个讨论,尽管语言规范为类描述了一个“ isCooperation”属性,但是实现几乎忽略了这个属性,而且既不用于动态代理,也不用于匿名类。合成字段和构造函数用于实现嵌套类(字节码中没有嵌套类的概念,只有源代码中有嵌套类的概念)。

我认为合成类的概念已经被证明是没有用的,也就是说,没有人关心一个类是否是合成的。对于字段和方法,它可能只用于一个地方: 确定在 IDE 类结构视图中显示什么——您希望显示普通方法和字段,但不希望显示用于模拟嵌套类的合成方法和字段。OTOH,你确实希望匿名类出现在那里。

例如,当您有一个 switch 语句时,java 创建一个以 $开头的变量。如果您想看到这方面的一个示例,可以查看包含 switch 语句的类的 Java 反射。当您在类中的任何地方至少有一个 switch 语句时,您将看到这些变量。

为了回答你的问题,我不相信你能够访问(除了反射)合成类。

如果您正在分析一个您不了解的类(通过反射) ,并且需要了解关于该类的非常具体和底层的事情,那么您可能最终使用与合成类有关的 Java 反射方法。这里唯一的“使用”是获取有关该类的更多信息,以便在代码中适当地使用它。

(如果您正在这样做,那么您可能正在构建其他开发人员可以使用的某种类型的框架。)

否则,如果您不使用反射,那么据我所知,合成类就没有实际用途。

综合类别/方法/界别:

这些东西对虚拟机来说很重要:

class MyOuter {


private MyInner inner;


void createInner() {
// The Compiler has to create a synthetic method
// to construct a new MyInner because the constructor
// is private.
// --> synthetic "constructor" method
inner = new MyInner();


// The Compiler has to create a synthetic method
// to doSomething on MyInner object because this
// method is private.
// --> synthetic "doSomething" method
inner.doSomething();
}


private class MyInner {
// the inner class holds a syntetic ref_pointer to
// the outer "parent" class
// --> synthetic field
private MyInner() {
}
private void doSomething() {
}
}
}

如果我的方法正确,那么合成类就是动态生成的类,而不需要给它一个明确的名称。例如:

//...
Thread myThread = new Thread() {
public void run() {
// do something ...
}
};
myThread.start();
//...

这将创建 Thread 的合成子类并重写其 run ()方法,然后实例化它并启动它。

当 Java 编译器编译某些构造(如内部类)时,它会创建 合成结构; 这些构造是在源代码中没有相应构造的类、方法、字段和其他构造。
用途: 合成构造使 Java 编译器能够在不更改 JVM 的情况下实现新的 Java 语言特性。但是,不同的 Java 编译器实现之间的合成构造可能有所不同,这意味着。类文件在不同的实现中也会有所不同。< br/> 参考文献: Docs.oracle.com

它们是由 JVM 在运行时为了调试目的而调用内部类的私有成员时创建的

JVM 在运行时为执行目的创建的方法、字段和类称为合成

Http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html

Http://javapapers.com/core-java/java-synthetic-class-method-field/

合成构造是在源代码中没有相应构造的类、方法、字段等。合成构造使 Java 编译器能够在不更改 JVM 的情况下实现新的 Java 语言特性。但是,不同的 Java 编译器实现之间的合成构造可能有所不同,这意味着。类文件在不同的实现中也会有所不同。

合成类不会出现在代码中: 它是由编译器组成的。 例如,Java 中由编译器构成的桥接方法通常是综合的。

public class Pair<T> {
private T first;
private T second;
public void setSecond(T newValue) {
second = newValue;
}
}




public class DateInterval extends Pair<String> {
public void setSecond(String second) {
System.out.println("OK sub");
}


public static void main(String[] args) throws NoSuchFieldException, SecurityException {
DateInterval interval = new DateInterval();
Pair pair = interval;
pair.setSecond("string1");
}
}

使用命令 javap -verbose DateInterval,您可以看到一个桥接方法:

public void setSecond(java.lang.Object);
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC

这是由编译器编写的,不会出现在代码中。

正如各种答案已经指出的那样,编译器可以生成各种构造(包括类) ,这些构造与源代码中的某些内容不直接对应。这些必须标明是合成的:

13.1二进制的形式

类或接口的二进制表示还必须包含以下所有内容:
[...]
11.如果 Java 编译器发出的构造与源代码中显式或隐式声明的构造不对应,则必须将其标记为合成构造,除非发出的构造是类初始化方法(JVMS 2.9)。
[...]

正如 @ Holger在对另一个问题的评论中指出的,这种构造的相关例子是表示方法引用和 lambdas 的 Class 对象:

System.out.println(((Runnable) System.out::println).getClass().isSynthetic());
System.out.println(((Runnable) () -> {}).getClass().isSynthetic());

产出:

true
true

虽然没有明确提到这一点,但它是从 15.27.4. Lambda 表达式的运行时评估 :

Lambda 表达式的值是对具有以下属性的类的实例的引用: [ ... ]

以及方法引用(15.13.3方法引用的运行时评估)的几乎相同的措辞。

由于这个类在源代码的任何地方都没有明确提到,所以它必须是合成的。

Java 中的合成类是什么?

synthetic类是由 Java 编译器生成的 .class文件,它不存在于源代码中。

synthetic类的示例用法: 匿名内部类

  • Java.text. DigitList $1 是一个 synthetic类,它是一个位于 < a href = “ https://openjdk.binarydoc.org/net.java/openjdk/13.0/classfile? classfilellocation = java.text.digital list”rel = “ nofollow noReferrer”> java.text. DigitList 内部的匿名内部类
  • 没有类似于 DigitList$1.java的源代码文件,但它是 DigitList.java中的一个内部文件

为什么要使用它?

它是 Java 编译器逻辑中生成 .class文件的一种机制

怎么用?

不,开发人员直接使用 没有

Java 编译器使用 synthetic生成 .class文件,然后 JVM 读取 .class文件以执行程序逻辑。

更多细节

  • 这个 文章详细解释了 synthetic
  • 这个 链接列出了 JDK中所有的 synthetic类出口