16

我有一个包含 2 个 HashMap 字段的类,如下所示-

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

现在,我只想在构造函数中传递一个映射,即 map1 或 map2 类型。但是,我无法使用不同类型的 HashMap 定义 2 个不同的构造函数。这是解决方法吗?

4

6 回答 6

27

几个选项:

1) 一个构造函数,它接受两个映射并且在传递 null 时是安全的。

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 回答
0

HashMap map1 和 HashMap map2 是完全不同的。它们不能互换。因此,您需要定义一个传递两个哈希映射的构造。

  public MyClass(HashMap<String, Integer> map1, HashMap<String, String> map2){
        ............
  }
于 2013-09-26T15:39:28.040 回答
0

我同意digitaljoel提供的答案......但是作为您的解决方法的第三个选项提供的 Builder Pattern 几乎没有改进。Builder Pattern 的主要优点之一是它消除了父类中的 setter 函数,客户端现在调用 builder 类的类 setter 函数来设置父类的实例变量。

public class MyClass{
    private Map<String, Integer> map1;
    private Map<String, String> map2;

    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() {
            return new MyClass(this);
        }

    }

    public MyClass(Builder b) {
        map1 = b.map1;
        map2 = b.map2;
    }

    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();
    }
}
于 2013-09-27T04:55:37.693 回答