web-dev-qa-db-ja.com

Javaの合成クラス

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

137
andHapp

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

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

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

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

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

15
Milhous

Javaには、実行時にクラスを作成する機能があります。これらのクラスは、合成クラスまたは動的プロキシと呼ばれます。

詳細については、 http://Java.Sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html を参照してください。

[〜#〜] cglib [〜#〜][〜#〜] asm [〜#〜] などの他のオープンソースライブラリも生成できます。合成クラス。JREで提供されるライブラリよりも強力です。

合成クラスは、Spring AOPやAspectJなどのAOP(Aspect Oriented Programming)ライブラリ、およびHibernateなどのORMライブラリで使用されます。

104

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

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

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

54
andHapp

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

これらのことは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() {
    }
  }
}
14
mrhuber

この説明 によると、言語仕様ではクラスの「isSynthetic」プロパティについて説明されていますが、これは実装ではほとんど無視され、動的プロキシまたは匿名クラスには使用されません。合成フィールドとコンストラクターは、ネストされたクラスを実装するために使用されます(バイトコードにはネストされたクラスの概念はなく、ソースコードにのみあります)。

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

8

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

実行時にJVMによって実行目的で作成されたメソッド、フィールド、クラスは、合成と呼ばれます

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

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

7
sathis

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

http://www.easymock.org/

3
user2427

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

2

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

13.1。バイナリの形式

クラスまたはインターフェイスのバイナリ表現には、次のすべても含める必要があります。
[...]
11。 Javaコンパイラーによって発行されたコンストラクトは、ソースコードで明示的または暗黙的に宣言されたコンストラクトに対応していない場合、発行されたコンストラクトがクラス初期化メソッド(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。Lambda式の実行時評価 から得られます。

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

メソッド参照のほぼ同一の表現( 15.13.3。メソッド参照の実行時評価 )。

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

2
Hulk

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

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

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

1
Ivan

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

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

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

0
JavaFresher