首页 > 代码库 > Java泛型
Java泛型
【Java泛型】
1、(2)以下的泛型转换,不正确,是一种编译错误。
Let‘s test your understanding of generics. Is the following code snippet legal?
List<String> ls = new ArrayList<String>(); // 1List<Object> lo = ls; // 2
Line 1 is certainly legal. The trickier part of the question is line 2. This boils down to the question: is a List
of String
a List
of Object
. Most people instinctively answer, "Sure!"
Well, take a look at the next few lines:
lo.add(new Object()); // 3String s = ls.get(0); // 4: Attempts to assign an Object to a String!
Here we‘ve aliased ls
and lo
. Accessing ls
, a list of String
, through the alias lo
, we can insert arbitrary objects into it. As a result ls
does not hold just String
s anymore, and when we try and get something out of it, we get a rude surprise.
The Java compiler will prevent this from happening of course. Line 2 will cause a compile time error.
参考:http://docs.oracle.com/javase/tutorial/extra/generics/subtype.html
2、Wildcards
So what is the supertype of all kinds of collections? It‘s written Collection<?>
(pronounced "collection of unknown"), that is, a collection whose element type matches anything. It‘s called a wildcard type for obvious reasons. We can write:
void printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e); }}
and now, we can call it with any type of collection. Notice that inside printCollection()
, we can still read elements from c
and give them type Object
. This is always safe, since whatever the actual type of the collection, it does contain objects. It isn‘t safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();c.add(new Object()); // Compile time error
Since we don‘t know what the element type of c
stands for, we cannot add objects to it. The add()
method takes arguments of type E
, the element type of the collection. When the actual type parameter is ?
, it stands for some unknown type. Any parameter we pass to add
would have to be a subtype of this unknown type. Since we don‘t know what type that is, we cannot pass anything in. The sole exception is null
, which is a member of every type.
3、Bounded Wildcards
Any drawing will typically contain a number of shapes. Assuming that they are represented as a list, it would be convenient to have a method in Canvas
that draws them all:
public void drawAll(List<Shape> shapes) { for (Shape s: shapes) { s.draw(this); }}
Now, the type rules say that drawAll()
can only be called on lists of exactly Shape
: it cannot, for instance, be called on a List<Circle>
. That is unfortunate, since all the method does is read shapes from the list, so it could just as well be called on a List<Circle>
. What we really want is for the method to accept a list of any kind of shape:
public void drawAll(List<? extends Shape> shapes) { ...}
There is a small but very important difference here: we have replaced the type List<Shape>
with List<? extends Shape>
. Now drawAll()
will accept lists of any subclass of Shape
, so we can now call it on aList<Circle>
if we want.
List<? extends Shape>
is an example of a bounded wildcard. The ?
stands for an unknown type, just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact a subtype of Shape
. (Note: It could be Shape
itself, or some subclass; it need not literally extend Shape
.) We say that Shape
is the upper bound of the wildcard.
There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now illegal to write into shapes
in the body of the method. For instance, this is not allowed:
public void addRectangle(List<? extends Shape> shapes) { // Compile-time error! shapes.add(0, new Rectangle());}
参考:http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Java泛型