Java 泛型通过示例进行简短解释

请参阅此常见问题以获取更多信息:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#SECTION1

以下是这个常见商要商记解决方案中的一些要点。

示例(安全类型):

類 Pair<X,Y> { 
  首先是私有X;
  私人Y第二;   公共對(X a1,Y a2){
    首先 = a1;
    第二個=a2;
  }
  public X getFirst() { 先回傳; }
  public Y getSecond() { 回傳第二個; }
  公無效setFirst(X arg){第一= arg; }
  公無效setSecond(Y arg){第二= arg; }
}

班級 一對 有兩個型別參數 X 和 是 。  當泛型類型時,它們被類型參數替換 一對 被實例化。例如,在聲明中 對<字串,日期> 類型參數 X 被類型參數替換 細繩 和 是 被替換為  日期 。
范围 X 和 是 是 類別的整個定義。  在此範圍內,兩種型別參數 X 和 是 类似类型的电影(有一些限制)。
类型参数允许电影边界来定义。边界参数所访问类型的最佳类型的最常用的范例中,我们不同最常用类型的方法 X 和 是 因此,这两种型号的参数是无界的。

示例(具体参数化类型):

公共無效列印對( 一對<串,長> 一對) {
  System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} 一對<串,長> 限制=新 一對<串,長> (“最大”,1024L);
列印對(限制);

範例(通配符參數化類型):

公共無效列印對( 對<?,?> 一對) {
  System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} 對<?,?> 限制=新 一對<串,長> (“最大”,1024L);
列印對(限制);

泛型類型的所有實例化都共用相同的執行時間類型表示,即原始類型的表示。例如,泛型類型的實例化 清單 , 例如 列表<日期> , 列表<字串> , 列表<長> 等在編譯時有不同的靜態類型,但動態類型相同 清單 在运行时。

演员阵容由两个连组成:

  • 編譯器在編譯時執行的靜態型別檢查
  • 虛擬機器在運行時執行的動態類型檢查。

靜態部分對無法成功的無意義的轉換進行排序,例如來自 細繩 那 日期 或來自 列表<字串> 那 列表<日期> 。

动态内容使用运行时类型资讯并在运行时参訳类型检查。它提出了一个 類別轉換異常 如果物件的動態類型不是強制轉換的目標類型(或目標類型的子類型)。具有動態部分的演員的例子是 目的 那 細繩 或來自 目的 那 列表<字串> 这些是所谓的世界转型,从超类型世界转型为子类型。

具体参数化类型的示例是 列表<字串> , 地圖<字串,日期> ,但不是 列出<?擴充 Number> 或者 Map<String,?> 。

有时预计 列表<物件> 將是 a 的超類型 列表<字串> , 因為 目的 是一個超類型 細繩 。  這種期望源自於這樣一個事實:數組存在這種類型的關係:  目的[] 是一個超類型 細繩[] , 因為 目的 是一個超類型 細繩 。 (這種類型的關係稱為 協方差 .) 組件類型的父子類型關係擴展到對應的陣列類型。對於泛型類型的實例化,不存在這樣的型別關係。 (參數化類型是 不是 协变。)

上海多类型类型的实例之间的结果超级子类型关系会产生完整的后果。这是一个结果。

例子:

無效 printAll(ArrayList<Object> c) {
  for (物件 o : c) 
    System.out.println(o);
} ArrayList<String> 清單 = 新 ArrayList<String>();
....填寫清單...
列印全部(列表);   // 錯誤

一個 ArrayList<String> 物件不能作為參數傳遞給需要 ArrayList<Object> 因為這兩種類型是同一泛型類型的實例化,但是對於 不同的 类型参数,是彼此不相容的度安。

具体参数化类型是其类型类型的具体实例。几乎是类似的类型;只是有一些限制。  无法使用于下一看:

  • 用於建立數組
  • 在例外處理中
  • 在類別文字中
  • 在一個 實例化 表達

电影类型为具体参数化类型的元素的排列是非法的。

例子

靜態無效測試(){
  對<整數,整數>[] intPairArr = 新 對<整數,整數>[10] ; // 錯誤
  addElements(intPairArr); 
  Pair<Integer,Integer> 對 = intPairArr[1];
  整數 i =pair.getFirst();
  對.setSecond(i);
}
靜態無效新增元素( 目的[] objArr) {
  objArr[0] = 新 Pair<Integer,Integer>(0,0);
  objArr[1] = new Pair<String,String>("","");      // 應因 ArrayStoreException 失敗
}

編譯器禁止建立其元件類型是特定參數化類型的數組,例如 對<整數,整數> 在我們的例子中。  我們在前面的條目中討論了為什麼編譯器限定一個是合理的 對<整數,整數>[] 作為非法的。  關鍵問題是編譯器和執行時間系統必須確保陣列是一個 同質 相同類型的元素的序列。  其中一種類型檢查,即虛擬機器在執行時執行的陣列儲存檢查,無法偵測到外來元素的違規插入。在範例中,第二個插入 新增元素 方法应贩法开,因为官们将补充字串添加到整数值储备中,但它并不存在。

如果不能使用保存方法,我们可以使用解决方法。

让我们得到3种性事的手机方法:

  • 原始型別數組
  • 無界通配符參數化類型的數組
  • 集合而不是數組

虽然具体参数化类型的排列是非法的,但具体参数化类型的组合是允许的。

通青符参数化类型是备型类型的实例化,从上往下是一个类型其他参数是通青符。 通青符参数化类型的示例是 收藏<?> , 列出<?擴充 Number> , 比較器<?超級弦> 和 對<字串,?> 。通配符參數化類型表示包含泛型類型的特定實例的型別族。  所使用的通配符的類型決定了哪些特定參數化類型屬於該族。  例如,通配符參數化類型 收藏<?> 表示所有實例化的家族 收藏 接口,無論類型參數如何。  通配符參數化類型 列出<?擴充 Number> 表示所有清單類型的族,其中元素類型是以下類型的子類型  數位 。  通配符參數化類型 比較器<?超級弦> 是所有實例化的家族 比較器 作為超類型的類型參數類型的接口 細繩。

通配符參數化類型不是常規意義上的類型(不同於非參數化類別/介面或原始類型)。

通配符參數化類型可用於鍵入(如非參數化類別和介面):

  • 作為方法的參數和返回類型
  • 作為欄位或局部引用變數的類型
  • 作為數組的組件類型作為其他參數化類型的類型參數
  • 作為強制轉換中的目標類型

不仅类型可以通用,方法也可以通用。静态和非静态方法和建凕数可以有类型参数。类参参数声明的形式与参型塞型的语言类似。类参数部分在当前方法的返回之前用括号分隔。

这是常见的例子 最大限度 計算未知類型元素集合中最大值的方法 一個 。

示例(一般方法):

類別集合{
  公共靜態 <A 擴充了 Comparable<A>> A 最大(集合< 一個 > xs) {
    迭代器< 一個 > xi = xs.iterator();
    一個 w = xi.next();
    while (xi.hasNext()) {
      一個 x = xi.next();
      if (w.compareTo(x) < 0) w = x;
    }
    返回w;
  }
} 

這 最大限度 方法有一個型別參數,名為 一個 。  它是該方法所處理的集合的元素類型的佔位符。類型參數有一個界限;它必須是一個子類型的類型 可比<A>

範例(相同的泛型類型,這次 和 邊界):

公共介面 Comparable<T> {
  公共 int CompareTo(T arg);
}
公共類別 TreeMap<Key 擴充 Comparable<Key> ,數據>{
  私有靜態類別 Entry<K,V> {
     K鍵;
     V值;
     Entry<K,V> 左 = null;
     Entry<K,V> 右 = null;
     條目<K,V>父級;
  }
  私有瞬態Entry<Key,Data> root = null;
  ...
  私有 Entry<Key,Data> getEntry(Key key) {
     Entry<Key,Data> p = 根;
     密鑰 k = 密鑰;
     while (p != null) {
       int cmp = k。 比較(p.key) ; 
       如果(cmp==0)
         返回p;
       否則如果(cmp < 0)
         p = p.左;
       別的 
         p = p.右; 
     }
     返回空值;
  }
  公共布爾包含Key(密鑰密鑰){
     回傳 getEntry(key) != null;
  }
  ...
}

在上面的例子中,類型參數 鑰匙 有界限 可比較<Key> 。  界限的規範有兩個作用:

  • 它允許存取綁定指定的方法 。  在該範例中,邊界 可比較<Key> 可以訪問 比較 我們要在實作中呼叫的方法 樹狀圖 班級。
  • 只有「在邊界內」的類型才能用於泛型類型的實例化。   在範例中,參數化類型例如 TreeMap<Number,String> 會被拒絕,因為類型 數位 不是 的子類型 可比較<數量> 。  參數化類型如 TreeMap<String,String> 會被接受,因為 String 類型在範圍內,也就是 String 的子類型 可比較<字串> .

什么类别、介面和枚举类型都可以用作类型参数绑定,公司巢状类型和内部类型。基度别和组合类型别都不能用作类型参数绑定。

示例(类型边界参数):

X0 <T 級擴展 整數 > { ... }      // 錯誤
X1 <T 類別擴展 目的[] > { ... } // 錯誤
X2 <T 級擴展 數位 > { ... }
X3 <T 級擴展 細繩 > { ... }
X4 <T 級擴展 可運行 > { ... }
X5 <T 級擴展 線程狀態 > { ... }
X6 <T 級擴展 清單 > { ... }
X7 <T 級擴展 列表<字串> > { ... }
X8 <T 級擴展 列出<?擴充 Number> > { ... }
X9 <T 級擴展 可以與<相媲美嗎?超級號碼> > { ... }
X10<T 類別擴展 Map.Entry<?,?> > { ... }

程式碼範例顯示了基本類型,例如 整數 和數組類型,例如 目的[] 允许作为类型参数绑定。

类别类型,例如 數位 或者 細繩 ,以及介面類型,例如 可運行 ,允许作为类型参数绑定。

枚举类型,例如 線程狀態 也允許作為類型參數綁定。 線程狀態 用作类型参数绑定的巢状类型的示例。非静态内部类型是允许的。

允许去类型作为类型参数绑定; 清單 这是一个例子。

参数化类型允许作为参数绑定,包括具体的参数化类型,例如 列表<字串> ,有界通配符參數化類型,例如 列出<?擴充 Number> 和 可以與<相媲美嗎?超長> ,以及無界通配符參數化類型,例如 Map.Entry<?,?> 作为通通符参数化类型的边界允许属于通通符运动的类型不同族好别作为类型别参数。

示例(通过青符参数化类型作为类型参数绑定):

X< 級 T 擴充 List<?擴充 Number> > {
  公共無效一些方法(T t){
    t.add(new Long(0L));    // 錯誤
    數字 n = t.remove(0);
  }
}
類別測試{
  公共靜態無效主(字串[] args){
     X<ArrayList< 長的 >> x1 = 新 X<ArrayList<Long>>(); 
     X<ArrayList< 細繩 >> x2 = 新 X<ArrayList<String>>(); // 錯誤
  }
}

類型的引用變數 時間 (型別參數)被視為通配符類型(型別參數綁定)的參考變數。  在我們的範例中,結果是編譯器拒絕呼叫採用型別參數所代表的「未知」類型的參數的方法,例如 列表.新增 ,因为界限是这些通过的通青符参数化类型。
同时绑定 列出<?擴充 Number> 確定可用作型別參數的型別。編譯器接受屬於該類型族的所有型別參數 列出<?擴充 Number> ,即所有子類型 清單 帶有一個子類型的類型參數 數位 。

一个类型参数可以作为另一个类型参数的边界。

示例(用作类型参数绑定的类型参数):

三人艙 <T> {
  私有 T fst、snd、trd;
  公共< U 延伸 T , V 延伸 T , 瓦 延伸 T > 三重(U arg1,V arg2,W arg3){
    fst = arg1;
    snd = arg2;
    trd = arg3;
  }
}

在此範例中,類型參數 時間 參數化類別的值用作型別參數的綁定 U ,  V 和 瓦 该类别的参数化实例是明确的。

作安公许使用一个类型参数作为一个类型其他参数的内容在全类型其他参数的绑定中

作为类别的边界允许存有您其全公公欢位、是付和巢状类型。只有当前子不能被访问,因为不能保证绑定的子类别与当前配置子相同。

示例(用作类型参数绑定的类别):

公開課 超級班 {     // 靜態成員
    公共枚舉 EnumType {這個,那個}
    公共靜態物件靜態字段;
    公共靜態無效靜態方法(){...}

    // 非靜態成員
    公共類別內部類別 { ... }
    公共物件非靜態字段;
    公共無效非靜態方法(){...}

    // 建構函式
    公共超類別(){...}

    // 私有成員
    私有對象私有欄位; 

    ...
}

公共最終類 SomeClass<T 擴展 超級班 > {
    私有T對象;
    公共 SomeClass(T t) { 物件 = t; } 

    公有字串 toString() {
        返回
         "靜態巢狀型別    : "+T.EnumType.class+"\n" 
        +"靜態字段          : "+T.staticField+"\n"
        +"靜態方法         : "+T.staticMethod()+"\n"
        +“非靜態巢狀型別:”+T.InnerClass.class+”\n”
        +"非靜態字段      : "+object.nonStaticField+"\n"
        +"非靜態方法     : "+object.nonStaticMethod()+"\n"
        +"建構子           : "+(new T())+"\n"                    //錯誤
        +"私有成員        : "+object.privateField+"\n"          // 錯誤 
        ;
    }
}

界線 超級班 提供對其巢狀類型、靜態欄位和方法以及非靜態欄位和方法的存取。  只有建構函數不可存取。  這是因為建構子不是繼承的。每個子類別都定義自己的建構函數,並且不需要支援其超類別的建構函數。  因此不能保證子類別 超級班 将是其超类别建様函数。

现状的美国 Enum<E 擴展了 Enum<E>> ” 出現的是聲明 列舉 包中的類 java語言 :

公共抽象類別 Enum<E 擴展了 Enum<E>> {
  ...
}

類型 列舉 是所有枚舉類型的公共基類。  在 Java 中,枚舉型別例如 顏色 被翻譯成一個類別 顏色 延伸 枚舉<顏色> 。超類的目的 列舉 是手机最好的枚举类型通用函数。

这是课程草图 列舉 :

公共抽象類別 枚举< 乙 扩展 Enum<E>> 实现 Comparable< 乙 >,可序列化 {
  私有最終字串名稱;
  公共最終字串名稱(){...}   私人最終 int 序數;
  公共最終 int ordinal() { ... }

  protected Enum(String name, int ordinal) { ... }

  公有字串           toString() { ... }
  公共最終布林值等於(物件其他){...}
  公共最終 int hashCode() { ... }
  protected Final Object clone() 拋出 CloneNotSupportedException { ... }
  公共最終 int 比較( 乙 o) { ... }

  公共最終類< 乙 > getDeclaringClass() { ... }
  公共靜態 <T 擴充 Enum<T>> T valueOf(Class<T> enumType, 字串名稱) { ... }
}

宣言中令人惊讶的特点“ Enum<E 擴展了 Enum<E>> “事实是新定义的类 列舉 及其新定义的类型参数 乙 出现在同一类型参数的边界中。  这意味着 列舉 类型必须为其子类型之一实例化。  为了理解为什么这是有意义的,请考虑每个枚举类型都被转换为 列舉 。

这是人为的枚举类型 顏色 :

枚举 顏色 {红、蓝、绿}

编译器将其翻译为以下类:

公开期末班 顏色 延伸 枚舉<顏色> {
  公共靜態最終顏色[]值(){返回(顏色[])$VALUES.clone(); }
  公共靜態顏色值(字串名稱){...}   私有顏色(字串 s,int i){ 超級(s,i); }

  公共靜態最終顏色紅色;
  公共靜態最終顏色藍色;
  公共靜態最終顏色綠色;

  私人靜態最終顏色$VALUES[];

  靜止的 {
    紅色=新顏色(“紅色”,0);
    藍色 = 新顏色("藍色", 1);
    綠色 = 新顏色("綠色", 2);
    $VALUES = (新顏色[] { 紅、藍、綠 });
  }
}

繼承的效果是 顏色 類型繼承了所有實作的方法 枚舉<顏色> 。  其中有 比較 方法。  這 顏色。比較 方法可能應該採取 顏色 作為一個論點。  為了實現這一點,班級 列舉 是通用的,並且 枚舉compareTo 方法需要 列舉 的型別參數 乙 作為一個論點。  結果,輸入 顏色 源自 枚舉<顏色> 繼承了一個 比較 方法需要一個 顏色 作为一个论点
我们剨枯声明" Enum<E 擴展了 Enum<E>> “我们可以看到这台歌曲有几个电影。

首先, 列舉 <E 延長 列舉 <E>> 「。它確保只有類型的子類型 列舉 允許作為類型參數。 (理論上,輸入 列舉 可以實例化自身,就像 枚舉<Enum> ,但设计并不是情简的,很难想象这样的实例化会情动的情况。)

上是,参数绑定类型是参数化类型 列舉 <E> ,它使用類型參數 乙 作為邊界的類型參數。此聲明確保了子類型和實例化之間的繼承關係 列舉 是這樣的形式 X 擴充了 Enum<X> 」。諸如「的子類型 X 擴充了 Enum<Y> ” 由于型号其他参数而无法声明 是 不會在界限內;僅子類型 枚舉<X> 他们在界线之内。

首先,一个事实是 列舉 首先是通用的。  這意味著類別的一些方法 列舉 接受一個參數或傳回未知類型的值(或依賴未知類型)。我們已經知道,這種未知類型稍後將成為一個子類型 X 的 枚舉<X> 。  因此,在參數化類型中 枚舉<X> ,這些方法涉及子類型 X ,並且它們被繼承到子類型中 X 。  這 比較 该方法是该方法的单个示例;它有一个特定的名称。

总话之,声明" Enum<E 擴展了 Enum<E>> ” 可以解讀為: 列舉 是一個泛型類型,只能為其子類型實例化,並且這些子類型將繼承一些有用的方法,其中一些方法採用子類型特定的參數(或以其他方式依賴子類型)。

類別的下界類型參數

類型參數可以有多個邊界,例如 類別 Box<T 擴充 Number> {...} 。但類型參數不能有下限,即諸如此類的構造 類 Box<T 偉大的 編號> {...} 答案是:这是毯子无意义的,因为公允许的话,官不会给你买任何人的东西。 让我们电影最多类型参数的这些设计著作来点什么为什么类别的下限类参数会让人们感到困惑。

类型参数的上限有三个action:

    1. 受限實例化。 上限限制可用於泛型類型實例化的類型集。  如果我們聲明一個 類別 Box<T 擴充 Number> {...} 那麼編譯器將確保只有子類型 數位 可以用作類型參數。  也就是說,一個 盒子<數量> 或一個 框<長> 是允許的,但是 盒子<物件> 或者 盒子<字串> 會被拒絕

範例(由於類型參數的上限而限制實例化):
類別 Box<T 擴充 Number> { 
   私有T值; 
   公共框(T t) { 值 = t; } 
   ...
}  類別測試{ 
   公共靜態無效主(字串[] args){ 
       Box<Long> boxOfLong = 新 Box<Long>(0L);   // 美好的
       Box<String> boxOfString = new Box<String>(""); // 錯誤:字串不在範圍內
   }
}

  1. 存取非靜態成員。 上限允許存取上限的所有公共非靜態方法和欄位。  在實施我們的 類別 Box<T 擴充 Number> {...} 我們可以呼叫類別中定義的所有公共非靜態方法 數位 , 例如 intValue() 例如。  如果沒有上限,編譯器將拒絕任何此類呼叫。範例(由於類型參數的上限而存取非靜態成員):

類別 Box<T 擴充 Number> { 
   私有T值; 
   公共框(T t) { 值 = t; } 
   公共 int 增量() { 傳回值.intValue()+1; } // 如果沒有 Number 限制,<= 將會出錯
   ...
} 

    1. 類型擦除。 最左邊的上限用於類型擦除並替換字節碼中的類型參數。  在我們的 類別 Box<T 擴充 Number> {...} 所有出現的 時間 將被上限取代 數位 。  例如,如果類別 盒子 有一個類型的私有字段 時間 和一個方法 void set(T內容) 若要設定此私有字段,則該字段的類型為 數位 類型擦除後,該方法將被轉換為方法 void set(數字內容) .

示例(在类型撦除使用类型参数的上限 – 前 類型擦除):
類 Box< T 擴充數字 > { 
   私人的 時間 價值; 
   公共信箱( 時間 t) { 值 = t; } 
   ...
} 

      示例(在类型撦除使用类型参数的上限 –

後

      類型擦除):

 

類別框{ 
   私人的 數位 價值; 
   公共信箱( 數位 t) { 值 = t; } 
   ...
}

    此外,最左邊的上限出現在其他位置,例如自動插入的強制轉換和橋接方法。

如果類型參數允許有下限,它們會或應該有哪些副作用?如果一個結構如 類 Box<T 偉大的 編號> {...} 被允许了,这是老着什么? 对于下限参数界限的 3 个副作用 – 初始化实例化、访问非成员静态、类型撦除 – 对于下限是著作什么?

受限实例化。 编译器可以限制可用于具有下限类型参数的泛型类型实例化的类型集。  例如,编译器可以允许实例化,例如 盒子<數量> 和 盒子<物件> 从一个 盒子<T 偉大的 编号> 并拒绝实例化,例如 框<長> 或者 框<短> 。  这将是与类型参数上限所描述的限制性副作用一致的效果。

存取非靜態成員。 较低的类型参数界限不允许访问除从类继承的方法之外的任何特定方法 目的 。在示例中 盒子<T 偉大的 编号> 的超类型 數位 没有任何共同点,除了它们是引用类型,因此是引用类型的子类型 目的 。  编译器不能假设类型的字段 時間 属于类型 數位 或其子类型。  相反,类型字段 時間 可以是任何超类型 數位 , 例如 可串行化 或者 目的 。  调用诸如 intValue() 不再是类型安全的,编译器将不得不拒绝它。因此,较低的类型参数界限将无法访问类中定义的非静态成员 目的 因此与“无界限”具有相同的效果。

类型擦除 。  按照这条逻辑线,用最左边的下界替换类型参数的出现是没有意义的。  声明一个类似于构造函数的方法 盒子( 時間 t) 作为构造函数 盒子( 數位 t) 没有意义,考虑到 時間 被替换为超类型 數位 。  一个 目的 可能会在实例化中正确传递给构造函数 盒子<物件> 并且构造函数会拒绝它。  这绝对是错误的。   因此,类型擦除将替换所有出现的类型变量 時間 按類型 目的 ,了全其下限。同样,下限与「无界限」具有同样的效果。

你想知道两者都下载着什么吗? _和_ 允许上限吗? 就我个人的话,如果有允许的话,我什至不是安上,并且更愿意将其归档为「无法管理」。

底线是:什么这一切都是” 偉大的 「bound will buy you 是只有超類型的限制 數位 可以用作類型參數。  甚至這一點也常被誤解。  這並不意味著 類別 Box<T 超級 Number> {...} 僅包含超類型的實例 數位 正好这个 – 前前电影示例示例文帐に追加!

示例(在类型撦除使用类型参数的上限 – 前 類型擦除):

類 Box< T超級號碼 > {
   私人的 時間 價值;
   公共信箱( 時間 t) { 值 = t; }
   ...
}

示例(在类型撦除使用类型参数的上限 – 後 類型擦除):

類別框{
   私人的 目的 價值;
   公共信箱( 目的 t) { 值 = t; }
   ...
}

一個 類 Box<T 偉大的 編號> {...} 將透過類型擦除轉換為 盒子 含有一個 目的 字段及其建構函數將被轉換為 盒子(物件t) 。這與 類 Box<T 延伸 編號> {...} ,這將被翻譯成 盒子 含有一個 數位 字段及其建構函數將被轉換為 盒子(數量t) 。因此,一個 盒子<數量> 實例化自 類別 Box<T 擴充 Number> {...} 會不同於 盒子<數量> 實例化來自 類別 Box<T 超級 Number> {...} ,这家公司会电影混乱。 因此,下限对于类别的类型其他参数没有意义。

 


 

方法的下界類型參數

对于电影的参数类型可以时月,可以限制的类型参数有时会非常有用。

示例(这些因此下限的类型其他参数教述):

類 Pair<X,Y> {
   首先是私有X;
   私人Y第二;
   ...
   公共< 一個超級X , B超Y > B addToMap(Map<A,B> map) { // 錯誤:型別參數不能有下限
      返回map.put(第一,第二);
   }
}
類別測試{ 
   公共靜態無效主(字串[] args){ 
     Pair<String,Long> 對 = new Pair<>("ABC",42L);
     Map<CharSequence,Number> 映射 = HashMap<CharSequence,Number>();
     Number number =pair.addToMap(map);
   }
}

這 加入地圖() 方法將該對的內容新增至地圖。  任何可以容納超類型的映射 X 和 是 會做的。  地圖的 放() 如果映射中已存在該鍵的鍵值條目,則方法會傳回在映射中找到的給定鍵的值。  地圖的回傳值 放() 方法應從返回 加入地圖() 方法。  在這些情況下,人們希望宣告如上所示的方法:映射使用該對的類型參數的超類型和 加入地圖() 方法的传回类型就是这些剧类型。

由于编译器允许类型其他参数的下限,我们电影一个手机方法。

我们的方法是使用通通符,因为通通符可以下限。这是什么万用字元的方法是。

示例(使用通通符前面上一个示例步面是):

類 Pair<X,Y> {
   首先是私有X;
   私人Y第二;
   ...
   民眾 目的 加入地圖(地圖< ?超級X , ?超級Y > 地圖){ 
      返回map.put(第一,第二);
   }
}
類別測試{ 
   公共靜態無效主(字串[] args){ 
     Pair<String,Long> 對 = new Pair<>("ABC",42L);
     Map<CharSequence,Number> 映射 = HashMap<CharSequence,Number>();
     數量 數量 = (數字) 對.addToMap(地圖);
   }
}

它可以工作,只是無法根據需要聲明返回類型。  這將是以下的超類型 是 編譯器從映射類型捕獲,但沒有指定它的語法。  我們不能將返回類型聲明為“ ?超級Y “, 因為 ” ?超級Y ” 是通通符とはます类型,情报不允许作为类型。我们别无选择,安全使用 目的 相反地​​作為我們方法的返回類型。  這種相當不特定的返回類型反過來又迫使呼叫者 加入地圖() 方法將回傳值向下轉換 目的 其实际类型。这并不完全是我们的事。

另一种解决方法是使用 方法。不是用方法。

示例(使用静态手机上一个示例是):

類 Pair<X,Y> {
   首先是私有X;
   私人Y第二;
   ...
   民眾 靜止的 < 一個 , 乙 ,X 延伸 A ,Y 延伸 B > B addToMap(Pair<X,Y> 對, Map< 一個 , 乙 > 地圖){
      return map.put(pair.first,pair.second);
   }
}
類別測試{ 
   公共靜態無效主(字串[] args){ 
     Pair<String,Long> 對 = new Pair<>("ABC",42L);
     Map<CharSequence,Number> 映射 = HashMap<CharSequence,Number>();
     數量 數量 = 一對 .addToMap( 一對 ,地圖);
   }
}

通用的 加入地圖() 方法有四個型別參數:兩個佔位符 X 和 是 對於該對的類型和兩個佔位符 一個 和 乙 對於地圖的類型。 一個 和 乙 是超類型 X 和 是 , 因為 X 和 是   聲明為 一個 和 乙 作為它們的上限。 (注意,泛型方法的型別參數 X 和 是 與 一對 班級的 X 和 是 參數。  名字 X 和 是 被重用于夫型数值,使我们轻松美化为该类型参数。使用四个类型参数,我们可以根据声明精纯的回传类型:与地图的值相同。

示例(在备类型类别的静态学样中正视问题类型参数):

類某類 <T> {
  // 靜態初始值設定項、靜態欄位、靜態方法
  靜止的 {
    一些類< 時間 > 測試 = 新 SomeClass< 時間 >(); // 錯誤
  }
  私人的 靜止的 時間 全局資訊;          // 錯誤
  民眾  靜止的 時間 取得全域資訊(){        // 錯誤
    返回全域資訊;
  }
  // 非靜態初始化器、非靜態欄位、非靜態方法
  { 
    一些類< 時間 > 測試 = 新 SomeClass< 時間 >();
  }
  私人的        時間 本地資訊;
  民眾         時間 取得本地資訊(){ 
    返回本地資訊;
  }
  // 靜態巢狀類型
  民眾 靜止的 班級 失敗擴展異常{
    私人決賽 時間 資訊;           // 錯誤
    公共失敗( 時間 t) { 信息 = t; }      // 錯誤
    民眾 時間 getInfo() { 回傳訊息; }    // 錯誤
   }
  私人的 介面 可複製{
    時間 複製();                       // 錯誤
  }
  私人的 枚举 狀態 {
    有效、無效;
    私人的 時間 訊息; // 錯誤
    公共無效設定資訊( 時間 t) { 信息 = t; } // 錯誤
    民眾 時間 getInfo() { 回傳訊息; }    // 錯誤
  }
  // 非静态嵌套类型
  民眾 班級 访问器{
    民眾 時間 getInfo() { 返回本地信息; }
  }
}

该示例说明类型参数不能在泛型类的静态上下文中使用。  它还表明嵌套接口和枚举类型被视为类的静态类型成员。  只有内部类(即非静态嵌套类)可以使用封闭泛型类的类型参数。

接口类型参数的范围是接口的整个定义,任何字段或嵌套类型除外。  这是因为接口中定义的字段和嵌套类型是隐式静态的。

示例(在泛型接口中非法使用类型参数):

接口 SomeInterface <T> {
  // 场地
  一些類< 時間 > 值 = 新 SomeClass< 時間 >();  // 錯誤
  // 嵌套类型
  班級 访问器{
    民眾 時間 獲取資訊(){            // 錯誤
      傳回值.getGlobalInfo();
    }
  }
  // 方法
  時間 获取值();
}

该示例显示接口的字段是隐式静态的,因此类型参数不能在泛型接口的字段声明中的任何位置使用。  同样,嵌套类被视为静态嵌套类,而不是内部类,因此在嵌套类中的任何位置使用类型参数都是非法的。

嵌套静态类和接口的解决方法:

对于静态嵌套类和接口,这不是一个大灾难。  作为解决方法,我们可以生成静态类或接口本身。

示例(解决方法 – 生成嵌套静态类型):

类包装器 <T> {
  私人決賽 時間 对象;

  公共包裝( 時間 t) { theObject = t; }
  民眾 時間 getWrapper() { 返回 theObject; }   公共不可變 <T> 使不可变(){
        返回新的不可變的 <T> (对象);
  }
  公共可變 <T> makeMutable() {
        返回新的可變 <T> (对象);
  }
  私有靜態 <A> A makeClone(A theObject) { ... }

  公共靜態最終類別不可變 <A> { // 現在是泛型類別
        私人決賽 一個 对象;

        公共不可變( 一個 參數){
            theObject = makeClone(arg);
        }
        民眾 一個 getWrappedItem() {
            返回 makeClone(theObject);
        }
  }
  公共靜態類別可變 <A> {
        ... 相似的 ...
  }
}

對於巢狀枚舉類型沒有這樣的解決方法,因為它們不能是泛型的。

嵌套靜態類別的解決方法:

如果是静态静态类型的一个类,则前面的手机是可以静态类别转换为非静态内部类别的。

示例(手机时间 – 使用内部类别):

类包装器 <T> {
  私人決賽 時間 对象;

  公共包裝( 時間 t) { theObject = t; }
  民眾 時間 getWrapper() { 返回 theObject; }   公共可變 makeMutable() {
      返回 這。 新的可變(theObject);
  }
  公共不可變 makeImmutable() {
      返回 這。 新的不可變(theObject);
  }
  私有靜態 <A> A makeClone(A theObject) { ... }

  公共最終類別不可變{  // 不再是靜態類
      私人決賽 時間 对象;

      公共不可變( 時間 參數){
          theObject = makeClone(arg);
      }
      民眾 時間 getWrappedItem() {
          返回 makeClone(theObject);
      }
  }
  公共類別可變 
        ... 相似的 ...
  }
}

这种手机机会带来了头头的问题,因为所有内部类别都有 1 个小类类别的隆藏,其他可能有一些细节。在这个例子中,它们既不需要也不使用;隐藏的参考了。

范例(改进了最合的电视教要):

类包装器 <T> {
  私人決賽 時間 对象;

  公共包裝( 時間 t) { theObject = t; }
  民眾 時間 getWrapper() { 返回 theObject; }   公共可變 <T> makeMutable() {
      返回 this.new Mutable(theObject);
  }
  公共不可變 <T> 使不可变(){
      返回 this.new Immutable(theObject);
  }
  私有靜態 <A> A makeClone(A theObject) { ... }

  公共介面 不可變<S> {
      S getWrappedItem();
  }
  公共介面 可變<S> {
      S getWrappedItem();
      無效 setWrappedItem(S arg);
  }
  私人的 最終類別 ImmutableImplementation 實作 Immutable<T> { 

      私有最終 T theObject;

      公共 ImmutableImplementation(T arg) {
          theObject = makeClone(arg);
      }
      公用 T getWrappedItem() {
          返回 makeClone(theObject);
      }
  }
  私人的 可變實作類別 實現 Mutable<T> { 
        ... 相似的 ...
  }
}

如您所见,光套的公共介面内容是一般性的,而内部类别的封闭类别的类型参数。

 

 

 

 

 

发表回复