Javaの合成クラスとは何ですか?なぜそれを使用する必要があるのですか?どうすれば使用できますか?
Javaの合成クラスとは何ですか?なぜそれを使用する必要があるのですか?どうすれば使用できますか?
回答:
たとえば、switchステートメントがある場合、javaは$で始まる変数を作成します。この例を確認したい場合は、switchステートメントが含まれているクラスのJavaリフレクションを確認してください。クラスのどこかに少なくとも1つのswitchステートメントがある場合、これらの変数が表示されます。
あなたの質問に答えるために、私はあなたが(リフレクション以外の)合成クラスにアクセスできるとは思いません。
(リフレクションを介して)何も知らないクラスを分析していて、そのクラスについて非常に具体的で低レベルのことを知る必要がある場合、合成クラスに関係するJavaリフレクションメソッドを使用することになるかもしれません。ここでの唯一の「使用」は、クラスをコードで適切に使用するためにクラスに関する詳細情報を取得することです。
(これを行っている場合は、おそらく他の開発者が使用できるある種のフレームワークを構築しているでしょう。)
そうでなければ、リフレクションを使用しない場合、私が知っている合成クラスの実際的な使用はありません。
Javaには、実行時にクラスを作成する機能があります。これらのクラスは、合成クラスまたは動的プロキシと呼ばれます。
詳細については、http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.htmlを参照してください。
CGLIBやASMなどの他のオープンソースライブラリでも合成クラスを生成でき、JREで提供されるライブラリよりも強力です。
合成クラスは、Spring AOPやAspectJなどのAOP(アスペクト指向プログラミング)ライブラリ、およびHibernateなどのORMライブラリで使用されます。
Proxy.newProxyInstance(Runnable.class.getClassLoader(), new Class[]{Runnable.class}, (proxy, method, args1) -> null).getClass().isSynthetic() == false
java.lang.reflect.Member#isSynthetic
言う:このメンバーがコンパイラにより導入された場合はtrueを返します。それ以外の場合はfalseを返します。
java.lang.reflect.Member#isSynthetic
は元の質問とは無関係であると思います。メンバーは、フィールド、コンストラクター、およびメソッドです。元の質問は、合成メンバーではなく、合成クラスに関するものでした。Java 8では、ラムダ式が合成クラスを発生させます-他にどのような状況が発生するかわかりません。
合成クラス/メソッド/フィールド:
これらは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() {
}
}
}
この議論によるとに、言語仕様ではクラスの「isSynthetic」プロパティが記述されていますが、これは実装ではほとんど無視され、動的プロキシまたは匿名クラスには使用されません。ネストされたクラスの実装には、合成フィールドとコンストラクターが使用されます(バイトコードにはネストされたクラスの概念はなく、ソースコードにのみ存在します)。
合成クラスの概念は役に立たないことが単純に証明されたと思います。つまり、クラスが合成クラスであるかどうかは誰も気にしません。フィールドとメソッドの場合、おそらく1か所で使用されます。IDEクラス構造ビューに何を表示するかを決定するために、通常のメソッドとフィールドを表示したいが、ネストされたクラスをシミュレートするために使用される合成のものは必要ない場合。OTOH、あなたは匿名のクラスがそこに現れることを望んでいます。
これらは、デバッグ目的で内部クラスのプライベートメンバーを呼び出すときに、実行時にJVMによって作成されます。
実行時にJVMが実行時に作成するメソッド、フィールド、クラスは、合成と呼ばれます。
http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html
http://javapapers.com/core-java/java-synthetic-class-method-field/
また、合成クラスまたは動的プロキシは、実行時にインターフェイスまたは抽象クラスの実装を作成するためにEasyMockによって使用されます。
Javaコンパイラーが内部クラスなどの特定の構成体をコンパイルすると、合成構成体が作成されます。これらは、ソースコードに対応するコンストラクトを持たないクラス、メソッド、フィールド、およびその他のコンストラクトです。
用途:
合成構造により、JavaコンパイラはJVMを変更せずに新しいJava言語機能を実装できます。ただし、合成構造はJavaコンパイラの実装によって異なる可能性があります。つまり、.classファイルも実装によって異なる可能性があります。
リファレンス:docs.oracle.com
さまざまな答えがすでに指摘されているように、コンパイラーは、ソースコード内の何かに直接対応しないさまざまな構造(クラスを含む)を生成することができます。これらは合成としてマークする必要があります。
クラスまたはインタフェースのバイナリ表現は、次の全てを含める必要があります。
[...]
それが構築物に対応するソースコードで明示的または暗黙的に宣言しない場合、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。メソッド参照の実行時評価)。
このクラスはソースコードのどこにも明示的に記述されていないため、合成である必要があります。
私が正しく理解すれば、合成クラスはその場で生成されるクラスであり、明示的な名前を付ける必要はありません。例えば:
//...
Thread myThread = new Thread() {
public void run() {
// do something ...
}
};
myThread.start();
//...
これにより、Threadの合成サブクラスが作成され、run()メソッドがオーバーライドされて、インスタンス化されて開始されます。
Outer$1.class
。
Javaの合成クラスとは何ですか?
synthetic
クラスがある.class
ことにより、生成されたファイルJavaコンパイラとそれがソースコードに存在しません。
synthetic
クラスの使用例:匿名の内部クラス
synthetic
クラスであり、java.text.DigitList内の匿名の内部クラスですDigitList$1.java
が、それはの内部ファイルですDigitList.java
なぜそれを使用する必要があるのですか?
これは、.class
ファイルを生成するJavaコンパイラロジック内のメカニズムです。
どうすれば使用できますか?
いいえ、開発者は直接使用しません。
Javaコンパイラはファイルのsynthetic
生成に使用し.class
、JVMはその.class
ファイルを読み取ってプログラムロジックを実行します。
合成構造は、ソースコードに対応する構造を持たないクラス、メソッド、フィールドなどです。合成構造により、JavaコンパイラはJVMを変更せずに新しいJava言語機能を実装できます。ただし、合成構造はJavaコンパイラの実装によって異なる可能性があります。つまり、.classファイルも実装によって異なる可能性があります。
合成クラスはコードに表示されません。それはコンパイラによって構成されます。たとえば、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
これはコンパイラによって作成されました。コードには表示されません。