Как определить 2 конструктора с двумя типами HashMaps?

У меня есть класс с 2 полями HashMap следующим образом:

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

Теперь я хочу только передать одну из карт в конструкторе, то есть либо типа map1, либо map2. Однако я не могу определить 2 разных конструктора с HashMaps разных типов. Это обходное решение для этого?

Ответы

Ответ 1

Несколько вариантов:

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) Статическая фабрика (как указал Евгений Дорофеев ниже)

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
}

Ответ 2

Вы не можете: генераторы будут удалены во время этапа компиляции: скомпилированный код просто видит HashMap<Object, Object> в обоих случаях.

Техническое название этого процесса - стирание типа. См. http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Во многом это делает Java-дженерики уступающими С++-шаблонам.

Ответ 3

В качестве обходного пути вы можете использовать статические методы factory с разными именами

Ответ 4

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 во время выполнения...

Ответ 5

HashMap map1 и HashMap map2 совершенно разные. Они не могут быть взаимозаменяемыми. Итак, вам нужно определить конструкцию, проходящую через два хэш-карты.

  public MyClass(HashMap<String, Integer> map1, HashMap<String, String> map2){
        ............
  }

Ответ 6

Я согласен с ответом digitaljoel... Но может быть несколько улучшений в Шаблоне Builder, представленном в качестве третьего варианта для вашего обходного пути. Одним из основных преимуществ шаблона Builder является то, что он устраняет функции setter из родительского класса, и клиент теперь вызывает функции, подобные тире, из класса builder для установки переменных экземпляра родительского класса.

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();
    }
}