接口中的Java泛型类型参数方法

5

我想在这里实现的目标是让子类决定是否要将java.lang.String或java.util.HashMap作为参数传递给query()方法。 接口只需要声明子类必须实现query方法,但我不关心子类希望传递哪种类型的参数。

我有一个接口如下:

interface A<T>{
    public void query(T type);
}

两个子类如下:

public class B implements A<String> {
    public void query(String type);
}

public class C implements A<HashMap> {
    public void query(HashMap type);
}

然后我有一个工厂类来生产B或C:

public class AFactory {
    public static A<?> getType(String type)  {
        if(type.equals("B")){
            return new B();
        } else if(type.equals("C")) {
            return new C();
        } 
   }
}

这个想法是客户端可以使用以下接口而无需依赖于B、C等内容:

A instance = AFactory.getType("B");
String a = "test";
instance.query(a); 

这里的问题是:eclipse在实例.instance.query(a)行上报错:
类型A中的方法query(capture#2-of ?)不适用于参数(String)
我认为问题在于接口合同不知道query应该期望一个String还是HashMap。我唯一能想到的解决办法是将结果强制转换,如下所示:
B instance = (B)AFactory.getType("B");
String a = "test";
instance.query(a); 

但是,这样做会导致我依赖于B而不仅仅是A(接口),这是我一开始想要避免的。有没有办法在不依赖子类(在这种情况下,B和C)的情况下实现这一点呢?


编译器检查 A 实例并说:“我需要 T,而不是 String”,但你没有告诉它 T 是什么。就我所知。 - d1e
很好,明白了,谢谢@JMelnik - Shengjie
2个回答

6

正如Ernest所说,你需要将返回的值转换——A<String>A<?>更具体。

如果你愿意更改工厂方法的签名,你可以使用泛型来避免自己进行强制转换:

public static A<T> getType(Class<T> type) {
    if (type.equals(String.class)) {
        return new B();
    } else if (type.equals(HashMap.class)) {
        return new C();
    }
}

那么你的调用代码可能看起来像这样:
A<String> instance = AFactory.getType(String.class);
String a = "test";
instance.query(a);

如果你不能这样做,那么调用 getType() 的人将不得不进行强制转换。


+1 感谢你提到我,你的回答比我的好 :) - Ernest Friedman-Hill

1

你不需要将类型转换为 B -- 转换为 A<String>。这将为您提供 query(String),但不会在源代码中引入 B

@SuppressWarnings("unchecked")
A<String> instance = (A<String>) AFactory.getType("B");
String a = "test";
instance.query(a); 

我添加了@SuppressWarnings注释,因为如果没有它,你将会得到一个“不安全”的警告;你知道这个警告是错误的,在这种情况下注释是可以的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接