将亚型多态性与通用多态性相关联的危险
Java 5已將通用多態性引入Java生態系統。 即使我們都知道由于泛型類型擦除及其后果而引起的無數警告,這對Java語言還是一個很大的補充。 通用多態性(也稱為參數多態性 )通常與可能預先存在的亞型多態性正交。 一個簡單的例子是collections API
在上面的示例中,子類型ArrayList被分配給超類型List的變量。 同時,使用Integer類型對ArrayList進行參數化,可以將其分配給兼容的參數超類型? extends Number ? extends Number 。 在泛型多態性的上下文中這種子類型多態性的用法也稱為協方差 ,盡管當然也可以在非泛型上下文中實現協方差。
具有通用多態性的協方差
協方差對于泛型很重要。 它允許創建復雜的類型系統。 簡單的示例涉及將協方差與通用方法結合使用:
<E extends Serializable> void serialize(Collection<E> collection) {}上面的示例接受任何Collection類型,可以在調用站點使用諸如List , ArrayList , Set等類型將其子類型化。 同時,僅要求調用站點上的泛型類型參數是Serializable的子類型。 即它可以是List<Integer>或ArrayList<String>等。
將亞型多態性與通用多態性相關聯
于是人們常常被引誘去關聯兩種正交類型的多態性。 此類關聯的一個簡單示例是將IntegerList或StringSet專門IntegerList :
class IntegerList extends ArrayList<Integer> {} class StringSet extends HashSet<String> {}這是很容易看到明確的類型的數量會爆炸,如果你開始跨越亞型和泛型類型層次的笛卡爾積,希望通過創建之類的東西更精確地專門IntegerArrayList , IntegerAbstractList , IntegerLinkedList等。
使相關性通用
從上面可以看出,這種關聯通常會從類型層次結構中刪除通用性,盡管并不需要這樣做。 在以下更一般的示例中可以看出:
// AnyContainer can contain AnyObject class AnyContainer<E extends AnyObject> {} class AnyObject {}// PhysicalContainer contains only PhysicalObjects class PhysicalContainer<E extends PhysicalObject>extends AnyContainer<E> {} class PhysicalObject extends AnyObject {}// FruitContainer contains only Fruit, // which in turn are PhysicalObjects class FruitContainer<E extends Fruit>extends PhysicalContainer<E> {} class Fruit extends PhysicalObject {}上面的示例是一個典型的示例,其中誘使API設計人員將子類型多態性( Fruit extends PhysicalObject extends AnyObject )與通用多態性( <E> )相關聯,同時保持通用性,從而允許在FruitContainer添加其他子類型。 AnyObject當AnyObject應該知道其自己的子類型時,這會變得更加有趣。 這可以通過遞歸泛型參數來實現。 讓我們修復前面的示例
// AnyContainer can contain AnyObject class AnyContainer<E extends AnyObject<E>> {} class AnyObject<O extends AnyObject<O>> {}// PhysicalContainer contains only PhysicalObjects class PhysicalContainer<E extends PhysicalObject<E>>extends AnyContainer<E> {} class PhysicalObject<O extends PhysicalObject<O>>extends AnyObject<O> {}// FruitContainer contains only Fruit, // which in turn are PhysicalObjects class FruitContainer<E extends Fruit<E>>extends PhysicalContainer<E> {} class Fruit<O extends Fruit<O>>extends PhysicalObject<O> {}這里有趣的部分不再是容器,而是AnyObject類型層次結構,該結構將子類型多態與自己類型上的通用多態相關聯! 這也可以通過java.lang.Enum完成:
public class Enum<E extends Enum<E>> implements Comparable<E> {public final int compareTo(E other) { ... }public final Class<E> getDeclaringClass() { ... } }enum MyEnum {}// Which is syntactic sugar for: final class MyEnum extends Enum<MyEnum> {}危險所在?
枚舉和我們的自定義之間的細微差別AnyObject層次是事實MyEnum通過被終止的兩個正交分型技術遞歸自相關final ! 另一方面,除非將AnyObject子類型也AnyObject為最終類型,否則不應將其刪除。 一個例子:
// "Dangerous" class Apple extends Fruit<Apple> {}// "Safe" final class Apple extends Fruit<Apple> {}為什么final如此重要,或者換句話說,為什么在終止遞歸自相關(例如Apple之前)時必須小心AnyObject子類型? 這很簡單。 讓我們假設以下添加:
class AnyObject<O extends AnyObject<O>>implements Comparable<O> {@Overridepublic int compareTo(O other) { ... }public AnyContainer<O> container() { ... } }上述關于AnyObject.compareTo()約定意味著, AnyObject任何子類型只能與同一子類型進行比較。 以下是不可能的:
Fruit<?> fruit = // ... Vegetable<?> vegetable = // ...// Compilation error! fruit.compareTo(vegetable);層次結構中當前唯一可比較的類型是Apple:
Apple a1 = new Apple(); Apple a2 = new Apple();a1.compareTo(a2);但是,如果我們想添加GoldenDelicious和Gala蘋果怎么辦?
class GoldenDelicious extends Apple {} class Gala extends Apple {}我們現在可以比較它們!
GoldenDelicious g1 = new GoldenDelicious(); Gala g2 = new Gala();g1.compareTo(g2);這不是AnyObject作者的AnyObject !
這同樣適用于container()方法。 允許子類型協變地專門化AnyContainer類型,這很好:
class Fruit<O extends Fruit<O>>extends PhysicalObject<O> {@Overridepublic FruitContainer<O> container() { ... } }但是, GoldenDelicious和Gala的container()方法會GoldenDelicious ?
GoldenDelicious g = new GoldenDelicious(); FruitContainer<Apple> c = g.container(); 是的,它將返回一個Apple容器,而不是AnyObject設計人員想要的GoldenDelicious容器。
子類型多態和泛型多態跨越正交類型軸。 使它們相互關聯可能是類型系統中的設計氣味。 使它們在同一類型上關聯是危險的,因為很難正確處理。 用戶將嘗試終止基本類型的子類型上的遞歸泛型類型定義。 終止的原因是具有遞歸自綁定的基本類型很難使用的事實。 但是終止通常會出錯,因為它只能在final類上執行,而不能在常規類或接口上執行。
換句話說,如果您認為需要基于通用基類型的遞歸泛型類型定義,請仔細考慮,如果確實需要,并且您的類型用戶可以在final類中正確終止遞歸泛型類型定義。
翻譯自: https://www.javacodegeeks.com/2013/07/the-dangers-of-correlating-subtype-polymorphism-with-generic-polymorphism.html
總結
以上是生活随笔為你收集整理的将亚型多态性与通用多态性相关联的危险的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯微云的默认下载路径
- 下一篇: 什么是弹力 弹力的解释