24

I am having trouble understanding the following article: http://www.ibm.com/developerworks/java/library/j-jtp01255.html

Under,

Generics are not covariant

the author states,

Because ln is a List, adding a Float to it seems perfectly legal. But if ln were aliased with li, then it would break the type-safety promise implicit in the definition of li -- that it is a list of integers, which is why generic types cannot be covariant.

I can't understand the part where it says "if ln were aliased with li". What does the author means by alias?(reference?). The code snippet above the quoted line seems to illustrate WHAT is illegal in java and not WHY. It would be very helpful to me if somebody could explain with an example. Thanks in advance.

Flow
  • 23,572
  • 15
  • 99
  • 156
soocracy42
  • 251
  • 1
  • 2
  • 4
  • IIRC, generic types are not covariant because they could not change how arrays were implemented/used in previous versions of Java (backward compatibility), does it ring a bell to someone? – Rhangaun Apr 18 '10 at 02:12
  • @Skeptic, Arrays are an example of what a covariant generics implementation might look like - it would throw runtime exceptions. Java can't do that because the generics are erased at runtime, so it can only control it via limiting covariance. – Yishai Apr 18 '10 at 02:31
  • @Yishai, that problem with arrays was discussed by Steele in a presentation named "Growing a Language" which I can't seem to find right now. – Rhangaun Apr 18 '10 at 02:57
  • That IBM link appears to be dead, but there's a copy at the Wayback Machine: http://web.archive.org/web/20121104021805/http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html – wool.in.silver Nov 28 '13 at 13:51
  • @Skeptic the written version of the Steele presentation did not mention the array problem. However, it is quite a good read. It is at http://www.cs.virginia.edu/~evans/cs655/readings/steele.pdf or via the Wayback machine, http://web.archive.org/web/20131117030438/http://www.cs.virginia.edu/~evans/cs655/readings/steele.pdf – Eponymous Nov 18 '14 at 21:33

3 Answers3

55
List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415));

In Java, Integer inherits from Number(java.lang.Number), so intuitively, anything that is an Integer(java.lang.Integer) is also a number, but what that article points out is that with generics it does not work that way, because considering that example, you could end up putting a float (which is a Number) into a List<Integer>, which is illegal because a float is not an integer.

Conclusion: Generics are not covariant.

Note: I recommend you read Effective Java (2nd Edition) Chapter 5: Generics.

bakkal
  • 54,350
  • 12
  • 131
  • 107
  • Thanks. 8) I thought the explanation had nothing to do with the code snippet. Silly me. – soocracy42 Apr 18 '10 at 02:27
  • +1 for the reco to read Effective Java. I've been writing code for many years, and picked up EJ a month ago and immediately learned 5 or 6 hugely important strategies. – Kevin Day Apr 18 '10 at 04:14
  • This article is also immensely helpful: https://www.ibm.com/developerworks/java/library/j-jtp01255/index.html – Markus Jevring Apr 03 '12 at 11:35
  • 1
    A bit off topic but C# does allow collections to have a type of covariance in a safe manner. checkout http://mikehadlow.blogspot.co.uk/2009/10/collection-covariance-with-c-40.html – simbo1905 Jun 29 '12 at 12:35
  • So, if I had a method returning type `List` I could in principle safely return a `List` because the integer list would stop being referenced afterwards? (Not saying java supports this without warnings) – Thomas Ahle Aug 01 '14 at 06:41
11

If you could do something like this:

List<Float> foo;
List<Object> bar;

foo = new ArrayList<Float>();
bar = foo;

foo.add(1.0f);
bar.add("Hello");

things would go VERY wrong. In this example bar is an alias for foo, and if you could do it you would lose the type safety that are the main reason that generics exist.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • Thanks a lot. I wasn't sure about the alias part. This confirms my assumption was right. – soocracy42 Apr 18 '10 at 02:24
  • Ah! So now "Hello" is not only in `bar` (which would probably be fine), but also in `foo`. Finally it makes sense :) I guess then I could declare a list casting method, which would have to copy the list, hm. – Thomas Ahle Aug 01 '14 at 06:38
-2
public class vechicle {
void drive(){
}
}
class car extends vechicle{
        //Covariance
    vechicle getObject(){
        return new car();
    }
        //contravariance
    car getmyObject(){
        return (car) new vechicle(); 
    }
}