我有一个包含2个HashMap字段的类,如下所示 -
HashMap<String, Integer> map1;
HashMap<String, String> map2;
现在,我想只传递构造函数中的一个映射,即map1或map2的类型。但是,我无法使用不同类型的HashMap定义2个不同的构造函数。这是一个解决方法吗?
答案 0 :(得分:26)
一些选择:
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)一个构建器,允许您区分地图并正确构造对象(调用setter)
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
}
答案 1 :(得分:13)
你不能:在编译阶段,泛型被剥离:在两种情况下,编译的代码只看到HashMap<Object, Object>
。
此过程的技术名称为 type erasure 。见http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
在很多方面,Java泛型都不如C ++模板。
答案 2 :(得分:8)
作为一种解决方法,您可以使用具有不同名称的静态工厂方法
答案 3 :(得分: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的具体类型......
答案 4 :(得分:0)
HashMap map1和HashMap map2完全不同。它们不可互换。因此,您需要定义一个传递两个哈希映射的构造。
public MyClass(HashMap<String, Integer> map1, HashMap<String, String> map2){
............
}
答案 5 :(得分:0)
我同意digitaljoel提供的答案......但是,作为第3个选项提供的构思模式可能很少有改进。 Builder Pattern的一个主要优点是它从父类中删除了setter函数,客户端现在调用构建器类的类似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();
}
}