M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

型パラメータのスコープとシャドウ化の実験

Javaジェネリクスの復習をしてヘンなコードを書いてみた。「やってはいけない」のカタマリみたいなコードである。

package x;
class A {}
class X {} // ...(1)
public class Container<X extends A> { // ...(2)
	private X content; // ...(3)
	public <X> Container(X content) { // ...(4)
		// this.content = content; ...(5)
		assignHelper(content); // ...(6)
	}
	private void assignHelper(Object x) { 
		this.content = (X) x; // ...(7)
	}
	public X get() {  // ...(8)
		return content;
	}
	public boolean isEmpty() {
		return content == null;
	}
	
	public static<X extends A> Container<X> wrap(X wrappable) { // ...(9)
		return new Container<>(wrappable); // ...(10)
	}
}
  1. ただのpackageプライベートなクラスで、型名はX
  2. クラス・スコープの型パラメータX。クラスAを拡張した任意の型を示す。もちろんすぐ上で宣言されているクラスXとの間には何の関係もない。
  3. 同じ型のフィールド。クラスAを拡張した任意の型のインスタンスへの参照を格納できる。
  4. コンストラクタ・スコープの型パラメータX。クラスAうんぬんの制約はなし。クラス・スコープの同名のパラメータをシャドウ化してしまう。もちろん引数contentの型Xコンストラクタ・スコープの型パラメータX
  5. 結果このコンストラクタ内ではクラス・スコープの型パラメータXと同じ型のフィールドthis.contentへの代入が不可能になる。
  6. しかたないのでasignHelper(Object)を呼び出して代入を行う。
  7. このXはクラス・スコープの型パラメータXなのでキャストも代入も成功する。
  8. このXもクラス・スコープの型パラメータX
  9. このstaticメソッドシグネチャに登場するいずれもメソッド・スコープの型パラメータXで、前述のいずれのXとも無関係。
  10. しかしその宣言部でX extends Aと規定されているためContainer<X>が型として有効になりメソッド・スコープの型パラメータXの引数wrappableをともないコンストラクタを呼び出すことができる。