Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

君は合成コンストラクタを知っているか?(2)

また合成関係で疑問が出た。


そもそも合成コンストラクタについては下記参照で。
君は合成コンストラクタを知っているか!(Java) - Fight the Future じゅくのblog


staticネストクラスにprivate修飾子をつける。

package sample;

import java.lang.reflect.Constructor;

public class SyntheticSample {

	private InnerClass innerClass = new InnerClass();

	private static class InnerClass {}

	public static void main(String[] args) throws Exception {
		Constructor<?>[] constructors = InnerClass.class.getDeclaredConstructors();
		for (Constructor<?> constructor : constructors) {
			System.out.format("%s%n", constructor.toGenericString());
			System.out.format("  [ synthetic=%-5b ]%n", constructor.isSynthetic());
		}
	}

}

すると、こんな警告が出る。

Access to enclosing constructor SyntheticSample.InnerClass() is emulated by a synthetic accessor method.Incresing its visibility will improve your performance

InnerClassのコンストラクタ呼び出しは、合成アクセッサメソッドでエミュレートされている。可視性をあげるとパフォーマンスが上がるよ、と。


mainメソッドを実行すると、出力はこうなる。

private sample.SyntheticSample$InnerClass()
  [ synthetic=false ]
sample.SyntheticSample$InnerClass(sample.SyntheticSample$InnerClass)
  [ synthetic=true  ]

InnerClassのコンストラクタはデフォルトコンストラクタだけでなく、合成でもう1つ作られる。
InnerClassがprivateなクラスであるために、デフォルトコンストラクタもprivateとなる。
それではアウタークラスであるSyntheticSampleからアクセスできないために、コンパイラが合成コンストラクタを作るわけだ。


javapコマンドを使ってもう少し調べてみる。

#javap -c SyntheticSample$InnerClass
Compiled from "SyntheticSample.java"
class sample.SyntheticSample$InnerClass extends java.lang.Object{
sample.SyntheticSample$InnerClass(sample.SyntheticSample$InnerClass);
  Code:
   0:   aload_0
   1:   invokespecial   #15; //Method "<init>":()V
   4:   return

}

先ほどのとおり、「"":(Lsample/SyntheticSample$InnerClass;)V」がある。


アウタークラスであるSyntheticSampleもjavapする。

#javap -c SyntheticSample
Compiled from "SyntheticSample.java"
public class sample.SyntheticSample extends java.lang.Object{
public sample.SyntheticSample();
  Code:
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new     #12; //class SyntheticSample$InnerClass
   8:   dup
   9:   aconst_null
   10:  invokespecial   #14; //Method sample/SyntheticSample$InnerClass."<init>":(Lsample/SyntheticSample$InnerClass;)V
   13:  putfield        #17; //Field innerClass:Lsample/SyntheticSample$InnerClass;
   16:  return
}

「//Method sample/SyntheticSample$InnerClass."":(Lsample/SyntheticSample$InnerClass;)V」とあるので、合成コンストラクタを呼び出していることがわかる。

警告の解決策

staticネストクラスの修飾子をpackage privateにしたりして、可視性を上げれば警告は消えるよ。