次のように、2つの HashMap フィールドを持つクラスがあります-
HashMap<String, Integer> map1;
HashMap<String, String> map2;
ここで、コンストラクターでマップの 1 つだけを渡したいと思います。つまり、map1 または map2 のいずれかのタイプです。ただし、異なるタイプの HashMap を使用して 2 つの異なるコンストラクターを定義することはできません。それはこれの回避策ですか?
次のように、2つの HashMap フィールドを持つクラスがあります-
HashMap<String, Integer> map1;
HashMap<String, String> map2;
ここで、コンストラクターでマップの 1 つだけを渡したいと思います。つまり、map1 または map2 のいずれかのタイプです。ただし、異なるタイプの HashMap を使用して 2 つの異なるコンストラクターを定義することはできません。それはこれの回避策ですか?
いくつかのオプション:
1) 両方のマップを取り、null が渡されたときに安全な 1 つのコンストラクター。
public MyClass( Map<String, Integer> map1, Map<String, String> map2 ) {
if ( map1 != null ) { this.map1 = map1; }
if ( map2 != null ) { this.map2 = map2; }
}
2) 各マップのセッター
public MyClass {
private Map<String, Integer> map1;
private Map<String, String> map2;
public void setMap1( Map<String, Integer> map1 ) {
this.map1 = map1;
}
public void setMap2( Map<String, String> map2 ) {
this.map2 = map2;
}
}
3)マップを区別してオブジェクトを適切に構築できるビルダー(セッターを呼び出す)
public MyClass {
private Map<String, Integer> map1;
private Map<String, String> map2;
// pretend you don't want people to be able to swap out the map after construction so you protect the setter here.
protected void setMap1( Map<String, Integer> map1 ) {
this.map1 = map1;
}
protected void setMap1( Map<String, String> map2 ) {
this.map2 = map2;
}
// getters for the maps and other properties
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Map<String, Integer> map1;
private Map<String, String> map2;
public Builder withMap1( Map<String, Integer> map ) {
map1 = map;
return this;
}
public Builder withMap2( Map<String, String> map ) {
map2 = map;
return this;
}
public MyClass build() {
MyClass c = new MyClass();
// possibly conditional code that inspects the maps for specific values or validity
c.setMap1( map1 );
c.setMap2( map2 );
// initialization of other fields
return c;
}
}
public static void main( String[] args ) {
// sample usage
MyClass instance1 = MyClass.builder().withMap1(myMap1).build();
MyClass instance2 = MyClass.builder().withMap2(myMap2).build();
MyClass instance3 = MyClass.builder().withMap1(myMap1).withMap2(myMap2).build();
}
}
4) 静的ファクトリー (下記の Evgeniy Dorofeev の指摘による)
public MyClass {
private Map<String, Integer> map1;
private Map<String, String> map2;
// other properties
private MyClass() {}
public static MyClass withMap1(Map<String, Integer> map ) {
MyClass c = new MyClass();
c.map1 = map;
return c;
}
public static MyClass withMap2(Map<String, String> map ) {
MyClass c = new MyClass();
c.map2 = map;
return c;
}
// getters and setters
}
できません: ジェネリックはコンパイル段階で取り除かれます: コンパイルされたコードHashMap<Object, Object>
は両方のケースで表示されます。
このプロセスの技術名称は、タイプ消去です。http://docs.oracle.com/javase/tutorial/java/generics/erasure.htmlを参照してください。
多くの点で、Java ジェネリックは C++ テンプレートよりも劣っています。
回避策として、異なる名前の静的ファクトリ メソッドを使用できます。
public class MyObject<T> {
public MyObject(Map<String, T> map) {
// process map
}
}
次に、次を使用してオブジェクトを作成できます。
new MyObject<Integer>(map1);
new MyObject<String>(map2);
問題は、MyObject 内の一般的なマップで何をしたいですか?
別の解決策は次のとおりです。
public class MyObject {
public <T> MyObject(Map<String, T> map) {
// process map
}
}
型引数 T はコンパイル時に推論されるため、これはさらに簡単に使用できます。
new MyObject(map1);
new MyObject(map2);
ただし、実行時に T の具体的な型を判断することはできません...