java generics covariance
Asked Answered
U

3

26

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.

Ulane answered 18/4, 2010 at 2:9 Comment(5)
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?Salvation
@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.Omaromara
@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.Salvation
That IBM link appears to be dead, but there's a copy at the Wayback Machine: web.archive.org/web/20121104021805/http://www.ibm.com/…Saucy
@Skeptic the written version of the Steele presentation did not mention the array problem. However, it is quite a good read. It is at cs.virginia.edu/~evans/cs655/readings/steele.pdf or via the Wayback machine, web.archive.org/web/20131117030438/http://www.cs.virginia.edu/…Scary
S
56
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.

Sawyers answered 18/4, 2010 at 2:17 Comment(5)
Thanks. 8) I thought the explanation had nothing to do with the code snippet. Silly me.Ulane
+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.Conjurer
This article is also immensely helpful: ibm.com/developerworks/java/library/j-jtp01255/index.htmlAristocrat
A bit off topic but C# does allow collections to have a type of covariance in a safe manner. checkout mikehadlow.blogspot.co.uk/2009/10/…Antrum
So, if I had a method returning type List<Number> I could in principle safely return a List<Integer> because the integer list would stop being referenced afterwards? (Not saying java supports this without warnings)Highpriced
G
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.

Gothar answered 18/4, 2010 at 2:15 Comment(2)
Thanks a lot. I wasn't sure about the alias part. This confirms my assumption was right.Ulane
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.Highpriced
B
-2
public class vechicle {
void drive(){
}
}
class car extends vechicle{
        //Covariance
    vechicle getObject(){
        return new car();
    }
        //contravariance
    car getmyObject(){
        return (car) new vechicle(); 
    }
}
Butters answered 5/3, 2014 at 4:39 Comment(1)
java.lang.ClassCastException will raise at return (car) new vechicle();Epithelioma

© 2022 - 2024 — McMap. All rights reserved.