Java中的方差


Java憑藉其強大的面向物件程式設計特性,為程式設計師提供了多種機制來開發靈活高效的程式碼。其中一個經常被忽視但至關重要的概念是方差。理解方差對於掌握Java至關重要,尤其是在使用泛型和集合時。本文深入探討了Java中的方差,涵蓋了它的型別——協變、逆變和不變——及其實際應用。

理解方差

方差指的是更復雜型別之間的子型別關係與其組成部分之間的子型別關係是如何關聯的。簡單來說,它決定了當這些類用作型別引數時,類的型別層次結構是如何保持的。在處理泛型時,方差變得尤為重要,它提供了一個框架來確保型別安全,同時允許在賦值中具有一定的靈活性。

方差可以分為三種主要型別

  • 協變如果ClassB是ClassA的子類,則Collection可以被視為Collection的子類.

  • 逆變 − 如果ClassB是ClassA的子類,則Collection可以被視為Collection的子類.

  • 不變 − Collection和Collection之間沒有子型別關係,無論ClassA和ClassB之間是什麼關係。

讓我們更深入地研究每一個概念。

Java中的協變

Java中透過使用帶有extends子句的萬用字元來實現協變。讓我們考慮一個例子:

List<Animal> animals = new ArrayList<>();
<List<super Cat>cats=animals;

在這種情況下,您可以將Cat物件或其任何例項新增到cats中,但您不能從cats中讀取並將結果視為Cat,因為它可能包含Cat的任何超型別,包括Animal或Object。因此,您可以寫入cats,但不能以型別安全的方式從中讀取。

Java中的不變

不變是Java中的預設行為,這意味著Collection和Collection之間沒有子型別關係,無論ClassA和ClassB之間是什麼關係。這看起來可能比較嚴格,但對於型別安全至關重要。在Java中,List不是List的子型別, even though String is a subtype of Object. This is because Java collections are mutable and allowing such a relationship would lead to runtime type errors.

List<String> strings = new ArrayList<>();
// Compile error: Incompatible types
List<Object> objects = strings;

In the above example, even though String is a subtype of Object, List is not a subtype of List, hence the compilation error.

This feature might initially appear as a limitation, but it's a vital aspect of Java's type system to ensure that no unsafe operations are performed. If List were a subtype of List, you could add an Object that is not a String into a List, leading to a ClassCastException at runtime.

List<String> strings = new ArrayList<>();
// If this were allowed...
List<Object> objects = strings;
// ...this would put a non-String into a List<String>
objects.add(new Object());
String str= strings.get(0); // ClassCastException

This example illustrates why it's essential to maintain invariance for type safety.

Bounded Type Parameters and Variance

Covariance and contravariance are most commonly used with bounded type parameters. Bounded type parameters are a way of indicating that a type parameter must be a subtype (extends keyword) or a supertype (super keyword) of a certain type. This allows for flexibility in what types can be passed to a method while still maintaining type safety.

For example, you might have a method that operates on lists of Number and all its subclasses −

public <T extends Number> void processNumbers(List<T> numbers) { /* ... */ }

In this method, T is a bounded type parameter that must be a Number or a subtype of Number. This allows the method to operate on List, List, List, etc., demonstrating covariance

Conclusion

In conclusion, understanding variance in Java is critical for effectively working with generics and collections. It allows for flexible code while ensuring type safety.

Covariance, using the extends keyword, allows a subclass to stand in for a superclass, enabling more generic object handling. Contravariance, on the other hand, permits the superclass to substitute for a subclass, enabling the execution of broader actions on more specific objects.

Invariance preserves type safety by ensuring that collections of different types, even if related by inheritance, maintain their uniqueness and prevent runtime type errors.

更新於:2023年7月19日

205 次瀏覽

開啟你的職業生涯

完成課程獲得認證

開始學習
廣告
© . All rights reserved.