Java中的综合类


143

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


1
Java 8中所有“不在代码中”的答案都已过时,因为lambda可以实现为合成(非匿名)类。
OrangeDog's

公平地说,lambda仍然不是“严格地”在代码中显式定义的类。因此,“不在您的代码中”仍然有效。编译器会为您生成综合类,而无需在代码中进行明确定义。
ManoDestra '19

Answers:


15

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

要回答您的问题,我认为您不能访问(除了反射)综合类。

如果要分析的类(通过反射)一无所知,并且需要了解有关该类的非常具体和底层的知识,则可能最终会使用与合成类有关的Java反射方法。这里唯一的“用法”是获取有关该类的更多信息,以便在您的代码中正确使用它。

(如果执行此操作,则可能正在构建其他开发人员可以使用的某种框架。)

否则,如果您不使用反射,那么我就不知道合成类的实际用途。


1
是的,如果您可以提供示例,则示例代码会很好
。–

36
这不能回答问题。
达伍德·伊本·卡里姆

对于开关的情况,我不确定是否每个开关都会发生这种情况,但是对于带有枚举的开关,我已经观察到这种情况。编译器生成具有单个静态字段的匿名类,该类提供一个映射Enum.ordinal()-> 1,2,3 ...(因此一个无间隙的序列),然后lookupswitch指令在该序列上运行开关,而不是直接运行在普通的。
Radim Vansa 2015年

106

Java能够在运行时创建类。这些类称为合成类或动态代理。

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

其他开放源代码库,例如CGLIBASM,也允许您生成综合类,并且比JRE随附的库更强大。

诸如Spring AOP和AspectJ之类的AOP(面向方面​​编程)库以及诸如Hibernate之类的ORM库都使用了合成类。


6
动态代理不是综合类Proxy.newProxyInstance(Runnable.class.getClassLoader(), new Class[]{Runnable.class}, (proxy, method, args1) -> null).getClass().isSynthetic() == false
证明

3
的javadoc java.lang.reflect.Member#isSynthetic表示:如果此成员由编译器引入,则返回true;否则,返回true。否则返回false。
Guillaume Husta

我认为javadoc java.lang.reflect.Member#isSynthetic与原始问题无关。成员是字段,构造函数和方法。最初的问题是关于综合,而不是综合成员。在Java 8中,lambda表达式会产生综合类-我不确定它们还会出现其他什么情况。
杰里米·克里神父(Fr Jeremy Krieg)

54

好吧,我在Google上找到了第一个问题的答案:

如果某个类是由编译器生成的,则该类可能被标记为综合类,也就是说,它没有出现在源代码中。

这只是一个基本定义,但我在论坛主题中找到了它,没有任何解释。还在寻找更好的...


15

综合类/方法/字段:

这些对于虚拟机很重要。请看以下代码片段:

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() {
    }
  }
}

2
@CiroSantilli乌坎事件2016六四事件法轮功,不,只有合成访问方法。
Miha_x64

8

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

我认为综合类的概念已被证明是无用的,即没有人关心类是否为综合类。使用字段和方法时,它可能只用在一个地方:确定要在IDE类结构视图中显示的内容-您希望在其中显示普通的方法和字段,而不是用于模拟嵌套类的合成方法和字段。OTOH,您确实希望匿名类出现在这里。


@OrangeDog:是的,这就是我写的。
Michael Borgwardt's

由于Java 8-lambda和方法引用都使用了此功能,因此此答案似乎已过时。我添加了一个答案,证明了这一点
绿巨人



2

当Java编译器编译某些构造(例如内部类)时,它会创建综合构造。这些是类,方法,字段以及其他在源代码中没有相应构造的构造。
用途: 合成构造使Java编译器无需更改JVM即可实现新的Java语言功能。但是,合成构造在不同的Java编译器实现中可能有所不同,这意味着.class文件在不同的实现中也可能有所不同。
参考:docs.oracle.com


2

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

13.1。二进制形式

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

正如@Holger在对另一个问题的评论中指出的那样,此类构造的相关示例是表示方法引用和lambda的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。方法参考的运行时评估)。

由于此类未在源代码中的任何地方明确提及,因此必须是合成的。


1

如果我做对了,那么合成类就是一个动态生成的类,而不必给它一个明确的名称。例如:

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

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


3
我认为这是一个匿名的内部阶级
Kumar Abhinav 2014年

2
我必须同意@KumarAbhinav。并非所有匿名内部类都是合成的。请参阅:xinotes.net/notes/note/1339
bvdb 2014年

匿名内部类不会在Oracle JDK 1.8.0_45上生成综合类,它们会生成单独的名称为type的非综合类Outer$1.class
西罗Santilli郝海东冠状病六四事件法轮功2015年

1

什么是Java中的综合类?

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

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

为什么要使用它?

这是Java编译器逻辑内部生成.class文件的机制

如何使用?

不,开发者不要直接使用它。

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

更多细节

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

文章是非常有用的,谢谢你
JasonMing

0

综合构造是在源代码中没有相应构造的类,方法,字段等。合成构造使Java编译器无需更改JVM就可以实现新的Java语言功能。但是,合成构造在不同的Java编译器实现中可能有所不同,这意味着.class文件在不同的实现中也可能有所不同。


1
-1。在您的答案之前一年给出的答案中,逐字逐句地发布了相同的文本[ stackoverflow.com/a/24271953/1144395],此外,该答案还引用了文本出处的官方参考,并提供了格式以便于阅读。 。请不要贪婪地回答重复的垃圾邮件问题。
naki

0

合成类未出现在您的代码中:它由编译器组成。例如,由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

这是由编译器组成的。它不会出现在您的代码中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.