4

Possible Duplicate:
Why is List<Number> not a sub-type of List<Object>?

Isn't String a subtype of Object in Java?

Then, how come I cannot pass an object of type List<String> into a function that accepts List<Object> as a parameter? I can, though, pass such an object into a function that accepts List as a parameter.


You are confusing the parameterized type with the concrete type.

Given List<T>, T is the parameterized type.

List<String> isn't type related to List<Object> in any way, not anymore than List<String> is related to List<Number>. The type is List<String>, the entire signature is the type. But like with everything, there are exceptions; these are called Wildcard Parameterized Types.

List<?> is what is called an Unbounded Wildcard Parameterized Type, it works pretty much just like a raw type, they are semantically the same, but causes more compiler warnings about unsafe casting.

List<? extends Object> is a bounded Wildcard Parameterized Type, and would be a type that would allow you to put anything that extends Object but since every class in Java extends Object it isn't semantically any different than the first two options.

Now they would all function the same, but they would fail instanceof tests, they are not the same types.

In other words:

public void myfunction(final List<Object> list) {}

would only accept the type of List<Object>, List isn't related by type to List<Object> or List<?>, even though they all semantically function the same.

The type is either List or List<Object> or List<String>, the inheritance chain in the <> is not considered when the type of the List<T> is concerned, until you get into Wild Card Parameterized Types

Here are examples:

Collection<?> coll = new ArrayList<String>(); 
List<? extends Number> list = new ArrayList<Long>(); 

You can't instantiate a new Collection<?> only assign a concrete implementation to it.

List<Object> is the entire type.

Generics in Java aren't anything like the implementation in C++, other than the confusing name.

4

5 回答 5

15

Isn't String a subtype of Object in Java?

Yes it is, but that doesn't make List<String> a subtype of List<Object>.

Consider this example:

    List<String> l1 = new ArrayList<String>();
    List<Object> l2 = l1;  // This is a compilation error in real Java
    l2.add(new Integer(42));
    String oops = l1.get(0);

If (hypothetically) List<String> was subtype of List<Object>, then you'd end up assigning a Integer to a String variable in the last statement. In short, we would have broken static type safety.


I can, though, pass such an object into a function that accepts List as a parameter.

Yes, that is true. But then you are dealing with raw types and you have to use explicit type casts when pulling objects out of the list. For example, the above would need to be rewritten as follows:

    List<String> l1 = new ArrayList<String>();
    List l2 = l1;
    l2.add(new Integer(42));
    String oops = (String) l1.get(0);

Note that the type-cast means we've had to replace static type-safety with runtime type-safety. (And, of course, in this case the typecast will fail at runtime because the instance has the wrong type.)

于 2012-06-26T01:58:33.440 回答
3

In Java, List<S> is not a subtype of List<T> when S is a subtype of T. This rule provides type safety.

Let's say we allow a List<String> to be a subtype of List<Object>. Consider the following example:

public void foo(List<Object> objects) {
    objects.add(new Integer(42));
}

List<String> strings = new ArrayList<String>();
strings.add("my string");
foo(strings); // this is not allow in java
// now strings has a string and an integer!
// what would happen if we do the following...??
String myString = strings.get(1);

So, forcing this provides type safety but it also has a drawback, it's less flexible. Consider the following example:

class MyCollection<T> {
    public void addAll(Collection<T> otherCollection) {
        ...
    }
}

Here you have a collection of T's, you want to add all items from another collection. You can't call this method with a Collection<S> for an S subtype of T. Ideally, this is ok because you are only adding elements into your collection, you are not modifying the parameter collection.

To fix this, Java provides what they call "wildcards". Wildcards are a way of providing covariance/contravariance. Now consider the following using wildcards:

class MyCollection<T> {
     // Now we allow all types S that are a subtype of T
     public void addAll(Collection<? extends T> otherCollection) {
         ...

         otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T)
     }
} 

Now, with wildcards we allow covariance in the type T and we block operations that are not type safe (for example adding an item into the collection). This way we get flexibility and type safety.

于 2012-06-26T01:57:53.130 回答
3

您将参数化类型与具体类型混淆了。

给定List<T>,T是参数化类型。

List<String>与 type 没有List<Object>任何关系,与 . 没有任何List<String>关系List<Number>typeList<String>,整个签名type。但就像所有事情一样,也有例外。这些被称为Wildcard Parameterized Types

List<?>就是所谓的无界通配符参数化类型,它的工作方式与原始类型非常相似,它们在语义上是相同的,但会导致更多关于不安全强制转换的编译器警告。

List<? extends Object>是一个有界通配符参数化类型,并且将是一种允许您放置任何内容的类型,extends Object但由于 Java 中的每个类在extends Object语义上都与前两个选项没有任何不同。

现在它们的功能都相同,但是它们会instanceof通过测试,它们不是相同的类型。

换句话说:

public void myfunction(final List<Object> list) {}

只会接受typeof List<Object>,Listtypeto List<Object>or无关List<?>,即使它们在语义上都具有相同的功能。

typeisListList<Object>or ,当涉及到的类型时,不考虑List<String>中的继承链,直到您进入Wild Card Parameterized Types<>List<T>

以下是示例:

Collection<?> coll = new ArrayList<String>(); 
List<? extends Number> list = new ArrayList<Long>(); 

你不能实例化一个new Collection<?>只分配一个具体的实现给它。

List<Object>是整个类型。

Java 中的泛型与 C++ 中的实现完全不同,除了令人困惑的名称。

于 2012-06-26T01:54:07.840 回答
0

String is a subtype of Object, yes, but that does not mean that List is a subtype of List. That's just the way Java works. You can read more here.

于 2012-06-26T01:56:39.440 回答
0

Besides everything said above, to allow what you want, you need to explicitly declare the parameter as List<? extends T> (it means, accepts anything that is subclass of T including T), in this case, List<? extends Object> should work but List<Object> is limited to Object-templated lists

于 2012-06-26T02:05:09.247 回答