Javaの合成クラス


143

Javaの合成クラスとは何ですか?なぜそれを使用する必要があるのですか?どうすれば使用できますか?


1
ラムダは合成(匿名ではない)クラスとして実装できるため、「コードに含まれていない」という答えはすべてJava 8では古くなっています。
OrangeDog

公平を期すために、ラムダはまだ「厳密に」コード内で明示的に定義されたクラスではありません。したがって、「not in your code」は引き続き有効です。コンパイラーは、コードで明示的に定義することなく、合成クラスを生成します。
ManoDestra

回答:


15

たとえば、switchステートメントがある場合、javaは$で始まる変数を作成します。この例を確認したい場合は、switchステートメントが含まれているクラスのJavaリフレクションを確認してください。クラスのどこかに少なくとも1つのswitchステートメントがある場合、これらの変数が表示されます。

あなたの質問に答えるために、私はあなたが(リフレクション以外の)合成クラスにアクセスできるとは思いません。

(リフレクションを介して)何も知らないクラスを分析していて、そのクラスについて非常に具体的で低レベルのことを知る必要がある場合、合成クラスに関係するJavaリフレクションメソッドを使用することになるかもしれません。ここでの唯一の「使用」は、クラスをコードで適切に使用するためにクラスに関する詳細情報を取得することです。

(これを行っている場合は、おそらく他の開発者が使用できるある種のフレームワークを構築しているでしょう。)

そうでなければ、リフレクションを使用しない場合、私が知っている合成クラスの実際的な使用はありません。


1
あなたが例/提供することができればはい、サンプルコードが良いでしょう
ナノファラッド

36
これは質問の答えにはなりません。
Dawood ibnカリーム2014

スイッチの場合、これがすべてのスイッチで発生するかどうかはわかりませんが、列挙型のスイッチでこれが確認されています。コンパイラーは、マッピング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を返します。それ以外の場合はfalseを返します。
Guillaume Husta 2017

のjavadoc java.lang.reflect.Member#isSyntheticは元の質問とは無関係であると思います。メンバーは、フィールド、コンストラクター、およびメソッドです。元の質問は、合成メンバーではなく、合成クラスに関するものでした。Java 8では、ラムダ式が合成クラスを発生させます-他にどのような状況が発生するかわかりません。
Jeremy Krieg神父、

54

さて、私はグーグルで最初の質問への答えを見つけました:

クラスは、コンパイラーによって生成された場合、つまり、ソースコードに表示されない場合、合成としてマークされる可能性があります。

これは基本的な定義にすぎませんが、フォーラムのスレッドで見つかり、説明はありませんでした。まだより良いものを探しています...


15

合成クラス/メソッド/フィールド:

これらはVMにとって重要です。次のコードスニペットをご覧ください。

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」プロパティが記述されていますが、これは実装ではほとんど無視され、動的プロキシまたは匿名クラスには使用されません。ネストされたクラスの実装には、合成フィールドとコンストラクターが使用されます(バイトコードにはネストされたクラスの概念はなく、ソースコードにのみ存在します)。

合成クラスの概念は役に立たないことが単純に証明されたと思います。つまり、クラスが合成クラスであるかどうかは誰も気にしません。フィールドとメソッドの場合、おそらく1か所で使用されます。IDEクラス構造ビューに何を表示するかを決定するために、通常のメソッドとフィールドを表示したいが、ネストされたクラスをシミュレートするために使用される合成のものは必要ない場合。OTOH、あなたは匿名のクラスがそこに現れることを望んでいます。


@OrangeDog:はい、それは私が書いたものです。
Michael Borgwardt

Java 8-ラムダとメソッド参照がこの機能を利用しているため、この回答は古くなっているようです。私はそれを実証する回答
Hulk

7

これらは、デバッグ目的で内部クラスのプライベートメンバーを呼び出すときに、実行時にJVMによって作成されます。

実行時にJVMが実行時に作成するメソッド、フィールド、クラスは、合成と呼ばれます。

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

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


実行時ではなく、コンパイル時のことだと思います。
モストウスキー崩壊

@ sathis、JVMではなくjavacを意味しましたか?
Miha_x64

3

また、合成クラスまたは動的プロキシは、実行時にインターフェイスまたは抽象クラスの実装を作成するためにEasyMockによって使用されます。

http://www.easymock.org/


2

Javaコンパイラーが内部クラスなどの特定の構成体をコンパイルすると、合成構成体が作成されます。これらは、ソースコードに対応するコンストラクトを持たないクラス、メソッド、フィールド、およびその他のコンストラクトです。
用途: 合成構造により、JavaコンパイラはJVMを変更せずに新しいJava言語機能を実装できます。ただし、合成構造はJavaコンパイラの実装によって異なる可能性があります。つまり、.classファイルも実装によって異なる可能性があります。
リファレンス:docs.oracle.com


2

さまざまな答えがすでに指摘されているように、コンパイラーは、ソースコード内の何かに直接対応しないさまざまな構造(クラスを含む)を生成することができます。これらは合成としてマークする必要があります。

13.1。バイナリの形式

クラスまたはインタフェースのバイナリ表現は、次の全てを含める必要があります。
[...]
それが構築物に対応するソースコードで明示的または暗黙的に宣言しない場合、Javaコンパイラによって放出された11 A構築物は、合成としてマークされなければなりません、出力された構成がクラス初期化メソッド(JVMS§2.9)でない限り。
[...]

@Holgerが別の質問へのコメントで指摘しているように、そのような構成の適切な例は、メソッド参照とラムダを表すClassオブジェクトです。

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

出力:

true
true

これは明示的には言及されていませんが、 15.27.4以降です。ラムダ式の実行時評価

ラムダ式の値は、次のプロパティを持つクラスのインスタンスへの参照です:[...]

そして、メソッド参照のためのほとんど同じ表現(15.13.3。メソッド参照の実行時評価)。

このクラスはソースコードのどこにも明示的に記述されていないため、合成である必要があります。


1

私が正しく理解すれば、合成クラスはその場で生成されるクラスであり、明示的な名前を付ける必要はありません。例えば:

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

これにより、Threadの合成サブクラスが作成され、run()メソッドがオーバーライドされて、インスタンス化されて開始されます。


3
私はそれが匿名の内部階級だと思った
クマールアビナフ2014年

2
@KumarAbhinavに同意する必要があります。すべての匿名内部クラスが合成であるわけではありません。参照:xinotes.net/notes/note/1339
bvdb

匿名内部クラスは、Oracle JDK 1.8.0_45で合成クラスを生成せず、typeという名前の個別の非合成クラスを生成しますOuter$1.class
Ciro Santilli郝海东冠状病六四事件法轮功

1

Javaの合成クラスとは何ですか?

syntheticクラスがある.classことにより、生成されたファイルJavaコンパイラとそれがソースコードに存在しません。

syntheticクラスの使用例:匿名の内部クラス

  • java.text.DigitList $ 1syntheticクラスであり、java.text.DigitList内の匿名の内部クラスです
  • そして、のような名前のソースコードファイルはありませんDigitList$1.javaが、それはの内部ファイルですDigitList.java

なぜそれを使用する必要があるのですか?

これは、.classファイルを生成するJavaコンパイラロジック内のメカニズムです。

どうすれば使用できますか?

いいえ、開発者は直接使用しませ

Javaコンパイラはファイルのsynthetic生成に使用し.class、JVMはその.classファイルを読み取ってプログラムロジックを実行します。

もっと詳しく

  • この記事では説明しますsyntheticクラスについて詳しくします
  • このリンクsyntheticJDKのすべてのクラス出口をリストします

記事はあなたに感謝し、非常に便利です
JasonMing

0

合成構造は、ソースコードに対応する構造を持たないクラス、メソッド、フィールドなどです。合成構造により、JavaコンパイラはJVMを変更せずに新しいJava言語機能を実装できます。ただし、合成構造はJavaコンパイラの実装によって異なる可能性があります。つまり、.classファイルも実装によって異なる可能性があります。


1
-1。まったく同じテキストが逐語的に、あなたの1年前に与えられた回答[ stackoverflow.com/a/24271953/1144395]に投稿されました。さらに、その回答はさらに、テキストの出所である公式リファレンスを引用し、読みやすくするためのフォーマットを提供しました。回答が明らかに重複している質問を貪欲にスパムしないでください。
naki 2017

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

これはコンパイラによって作成されました。コードには表示されません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.