簡體   English   中英

在這種情況下如何避免泛型?

[英]How to avoid Generics in this case?

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>> ”在多個其他類中使用,可以是私有成員變量,也可以是方法返回類型。 由於屬性,似乎我必須將一些其他相關類定義為泛型類型,這會導致我的問題。

在這種情況下,有沒有辦法不將Matrix定義為泛型,但將“list”變量保持為泛型類型?

您的問題不在於通用實現,而在於其用法:

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>表示您正在綁定相對於方法調用的新泛型類型。 簡而言之,一個新的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? extends Matrix ,我們指定了正確的方差。 具體的泛型是不變的 ,因此List<Toyota>不是List<Car> ,即使ToyotaCar的子類。 如果我們希望Matrix協變的 ,那么我們不幸地需要Matrix上的邊界。 這實際上意味着,忽略Liskov的替換主體,我們基本上是引用提取器的具體子類( InfoExtractor ex vs Extractor ex ),特別是從可用性的角度來看(因為具體類可以返回正確的類型安全,而接口不能) 。

當您將列表中的矩陣的<T>指定為類級泛型類型時,這當然會得到更加清晰/干凈的處理。

這取決於你想做什么。

如果您打算使用Matrix來保存單一類型的屬性,那就是T,那么最好的方法似乎是您發布的編譯時間類型檢查。

如果從Matrix中刪除泛型類型T,則無法知道每個屬性的類型。 您可以從Matrix聲明中完全刪除T,並使用通配符作為Attribute變量。 雖然這將允許您在同一Matrix對象中存儲不同T類型的屬性,但它將刪除編譯類型檢查。 換句話說,使用Matrix的類必須知道期望什么類,並且可能將每個屬性轉換為期望的類。

Class Matrix{
   private String name;
   List<Attribute<?>> list;

   public Matrix(String name, T t){
     this.name = name;
     list = new ArrayList<>();
     list.add(new Attribute<>(t)); 
  }
}

添加Class變量並將Class對象保存在屬性中可以幫助您在運行時保留一些信息以標識屬性內對象的類。

class Attribute<T>{
   private T attr;
   private final Class<T> clazz;

   public Attribute(T attr, Class<T> clazz){
      this.attr = attr;
      this.clazz=clazz;
   } 

    public Attribute(T attr){
      this.attr = attr;
      Objects.requireNonNull(attr);
      this.clazz= (Class<T>) attr.getClass();
   } 
}

使用此方法,原始構造函數只能用於非null值,否則類對象應由程序員提供。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM