class Attribute<T>{
private T attr;
public Attribute(T attr){
this.attr = attr;
}
}
Class Matrix<T>{
private String name;
List<Attribute<T>> list;
public Matrix(String name, T t){
this.name = name;
list = new ArrayList<>();
list.add(new Attribute<T>(t));
}
}
interface Extractor<T> {
public List<Matrix<T>> extract();
}
InfoExtractor implements Extractor<String>{
public List<Matrix<String>> extract(){
List<Matrix<String>> matrixList = new ArrayList<>();
// The problem is here!!!!
matrixList.add(new Matrix<String>("abc"));
}
}
Document<T>{
Map<String, List<Matrix<T>>> matrixMap;
public void process(){
...
Extractor<T> extractor = (Extractor<T>) new StringExtractor(sent);
List<Matrix<T>> matrix = extractor.extract(...);
}
我的问题是,有没有办法避免将 Matrix 定义为通用类型?我想避免的原因是“List<Attribute<T>>
”在多个其他类中使用,作为私有(private)成员变量或方法返回类型。由于 Attribute,我似乎也必须将一些其他相关类定义为泛型类型,这导致了我的问题。
在这种情况下,有没有办法不将 Matrix 定义为泛型,而是将“列表”变量保留为泛型?
最佳答案
您的问题不在于通用实现,而在于它的用法:
class InfoExtractor implements Extractor{
// The problem is actually here
public <T> List<Matrix<T>> extract(){
List<Matrix<T>> matrixList = new ArrayList<>(); //and here
// "The problem is here!!!!"
matrixList.add(new Matrix<String>("abc"));
}
}
<T>
表示您正在绑定(bind)一个与方法调用相关的新泛型类型。简而言之,一个新的 T
仅为此方法的执行键入。你还做了一个List<Matrix<T>>
但随后尝试添加一个新的 Matrix<String>
后退。如果您知道该列表将属于 Matrix<String>
类型, 那么您可以在 InfoExtractor
中指定:
//If you cannot generify the interface for some reason
interface Extractor {
public List<? extends Matrix<?>> extract(); //explained at bottom
}
//IDEALLY, then implement Extractor<String> instead
interface Extractor<T> {
public List<Matrix<T>> extract();
}
class InfoExtractor implements Extractor { //or Extractor<String>
public List<Matrix<String>> extract() {
List<Matrix<String>> matrixList = new ArrayList<>();
matrixList.add(new Matrix<>("abc"));
return matrixList;
}
}
当然,你可以看到Extractor
的方法签名变了。由于在返回类型上使用嵌套泛型,编译时的类型匹配会变得有点困惑。 <?>
因为 Matrix 是不言自明的,我们在 Matrix 中返回多个可能未知的类型。
通过指定 ? extends Matrix
在 Extractor
,我们正在指定适当的方差。具体的泛型是不变的,因此是List<Toyota>
不是 List<Car>
, 即使Toyota
是 Car
的子类.如果我们想要 Matrix
是协变,那么不幸的是我们也需要 Matrix 上的边界。这意味着实际上,忽略 Liskov 的替换原则,我们实际上是在引用提取器的具体子类( InfoExtractor ex
vs Extractor ex
),尤其是从可用性的角度来看(因为具体类可以返回适当的类型安全,而接口(interface)不能)。
当然,当您指定 <T>
时,处理起来会更加理智/干净。将列表中的矩阵作为类级别的泛型类型。
关于java - 在这种情况下如何避免泛型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44450073/