Home  >  Article  >  Java  >  Covariance of generics in Java

Covariance of generics in Java

高洛峰
高洛峰Original
2016-11-22 17:56:441437browse

I encountered a problem at work, described in code as follows:

package test;import java.util.LinkedList;
import java.util.List;public class ListTest {
    public void func(List<Base> list) {
    }
    public static void main(String args[]) {
        ListTest lt = new ListTest();
        List<Derived> list = new LinkedList<Derived>();
        lt.func(list); // 编译报错    }
}class Base {
}class Derived extends Base {
}

You need to write a function func here, which can take the list of Base as a parameter. I thought it was okay to pass a Derived list, because Derived is a derived class of Base, so Derived's list should also be a derived class of Base's list, but the compiler reported an error.

To find out the reason, I checked some information on the Internet: Java's generics are not covariant.

Covariance and contravariance of generics are both terms. The former refers to the ability to use a type that is less derived (less specific) than the originally specified derived type, and the latter refers to the ability to use a derived type that is smaller than the originally specified derived type. A more derived (more specific) type.

For example, generics in C# support covariance:

IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;

But Java’s generics do not support covariance. Code similar to the above cannot be compiled in Java.

But interestingly, arrays in Java support covariance, for example:

Integer[] intArray = new Integer[10]; 
Number[] numberArray = intArray;

Summary: Java's generics do not support covariance, and it is more from the perspective of type safety. This design is not necessarily necessary. For example, C# does not use this design. It can only be said that the designers of Java made a choice between ease of use and type safety.

Finally, back to the original question, to implement such a method func, you can modify it to:

public void func(List list) {
}

or use a parameterized type:

public <T> void func(List<T> list) {
}

But this also has problems, it will blur the parameter type of func. A better way is not to change func, but to pass a Base type List when passing parameters, which requires converting elements to Base type when adding them to the List.

PS: By limiting the parameter type:

public void func(List<? extends Base> list) {
}


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn