16

次のように、2つの HashMap フィールドを持つクラスがあります-

HashMap<String, Integer> map1;
HashMap<String, String> map2;

ここで、コンストラクターでマップの 1 つだけを渡したいと思います。つまり、map1 または map2 のいずれかのタイプです。ただし、異なるタイプの HashMap を使用して 2 つの異なるコンストラクターを定義することはできません。それはこれの回避策ですか?

4

6 に答える 6

27

いくつかのオプション:

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
}
于 2013-09-26T15:36:26.973 に答える
14

できません: ジェネリックはコンパイル段階で取り除かれます: コンパイルされたコードHashMap<Object, Object>は両方のケースで表示されます。

このプロセスの技術名称は、タイプ消去です。http://docs.oracle.com/javase/tutorial/java/generics/erasure.htmlを参照してください。

多くの点で、Java ジェネリックは C++ テンプレートよりも劣っています。

于 2013-09-26T15:36:22.363 に答える
8

回避策として、異なる名前の静的ファクトリ メソッドを使用できます。

于 2013-09-26T15:37:48.807 に答える
1
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 の具体的な型を判断することはできません...

于 2013-09-26T15:38:05.000 に答える