Poojan
Poojan

Reputation: 3332

How to define 2 constructors with 2 different type of HashMaps?

I have a class with 2 HashMap fields as follows-

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

Now, I want to only pass one of the maps in the constructor, that is either of type of map1 or of map2. However, I am not able to define 2 different constructors with HashMaps of different types. Is that a workaround for this?

Upvotes: 16

Views: 2088

Answers (6)

digitaljoel
digitaljoel

Reputation: 26574

A few options:

1) One constructor that takes both maps and is safe when passed a null.

public MyClass( Map<String, Integer> map1, Map<String, String> map2 ) {
    if ( map1 != null ) { this.map1 = map1; }
    if ( map2 != null ) { this.map2 = map2; }
}

2) Setters for each map

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) A builder that allows you to differentiate between the maps and constructs the object properly (calling the setters)

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) Static factory (as pointed out by Evgeniy Dorofeev below)

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
}

Upvotes: 27

Masudul
Masudul

Reputation: 21971

HashMap map1 and HashMap map2 are completely different. They can't be interchangeable. So, you need define a construction passing two hash maps.

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

Upvotes: 0

Kushagra Thapar
Kushagra Thapar

Reputation: 187

I agree with the answer provided by digitaljoel ... But there can be few improvements to Builder Pattern provided as 3rd option for your workaround. One of the major advantages of Builder Pattern is that it eliminates the setter functions from parent class, and the client now calls the setter-like functions of builder class to set instance variables of parent class.

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

Upvotes: 0

isnot2bad
isnot2bad

Reputation: 24454

public class MyObject<T> {
    public MyObject(Map<String, T> map) {
         // process map
    }
}

Then you can create your object with:

new MyObject<Integer>(map1);
new MyObject<String>(map2);

The question is: What do you want to do with a generic map inside MyObject...?

Another solution is:

public class MyObject {
    public <T> MyObject(Map<String, T> map) {
        // process map
    }
}

This is even more easy to use, because the type argument T is inferred at compile time:

new MyObject(map1);
new MyObject(map2);

However, you will not be able to determine the concrete type of T at runtime...

Upvotes: 1

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136062

As a workaround you could use static factory methods with different names

Upvotes: 8

Bathsheba
Bathsheba

Reputation: 234785

You can't: generics get stripped out during the compilation stage: the compiled code just sees HashMap<Object, Object> in both cases.

The technical name for this process is type erasure. See http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

In many ways that makes Java generics inferior to C++ templates.

Upvotes: 14

Related Questions