2012-03-18 155 views
5

可能重复:
Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
Java Generics — Assigning a list of subclass to a list of superclass原始类型和泛型 - Java的

随着原料的类型,你可以很容易地说这句话。

[...] // MyClass is generic with upper bound of Object 

MyClass c = new MyClass<Double>(); 

[...] 

但是,这是不允许的

MyClass<Number> c = new MyClass<Double>() 

我不明白这是为什么。我的书告诉我为什么第二个不起作用,因为你不能将Integer加到MyClass<Double>。它没有解释的是为什么MyClass<Double>MyClass<Object>(或等价的原始类型形式)的子类,因为double是对象的子类。

那么为什么第一个允许,如果第二个表格不是。请意识到我对此很陌生。

编辑:更进一步在第一个例子中,如果Number是上限,会发生什么?

你可以在这里看到类型擦除的影响

class Untitled { 
public static void main(String[] args) { 

} 
public static<T> void c(T t) 
{ 
    t.SubClassMethod();// this won't work because class Object has no such method. But if I change the upperbound to SubClass it will. 
      t.toString() // this will because class Object has such a method 
} 
} 

我的观点是,它为什么要不管是什么,如果它最终成为为上反正约束处理通用声明?

+0

我的问题是相反的,我问你为什么可以分配到一个子类的原始类型 – rubixibuc 2012-03-18 23:47:47

+0

这个问题的前提也是错误的,因为类型擦除它唯一担心的是上限是否与方法,并使用该类型来检查投射。至少这是我读过的 – rubixibuc 2012-03-18 23:49:58

回答

3

消除您的困惑的第一件事是了解原始类型是而不是泛型系统的一部分。它绝不等于Something<Object>。基本上,Raw Type存在的原因仅仅是为了向后兼容。当在Java 5中引入泛型时,一些现有的类和接口被追溯为泛型。为了在Java 5或更高版本的编译器中编译没有泛型声明的旧代码,原始声明是合法的。

原始类型行为方式与参数化类型行为方式之间的任何比较都有点根本上是虚假的。设计的目的不是原始类型被认为是声明参数的“替代”。使用原始类型的新代码是不正确的代码。编译它是合法的,以便旧代码仍然有效。

我的观点是,为什么它应该声明通用被声明为 如果它最终被视为上限呢?

因为泛型的整个点是为了防止ClassCastException。当有人(例如某人将对象从列表中取出并将其分配给他们期望的特定类型)时,它将被视为实际声明的类型。编译器正在做出承诺,保证它会成功,所以它必须限制进出的内容。

+0

在做了一些深入研究之后,我回答了我自己的问题,并且你完美地回答了这个问题。是的,它是有道理的,如果返回类型不同意会发生什么。谢谢你澄清这一点。 – rubixibuc 2012-03-19 00:35:19

+0

我唯一不同意的是它被视为声明类型而不是上限。当方法或类编译我知道发生的唯一强制转换回函数返回时的参数化类型。由于类型擦除,其他所有内容都被隐式转换为上限并且在方法中被如此处理。请让我知道,如果我对此正确。 – rubixibuc 2012-03-19 00:39:07

+0

雅,这就是我在我的磨合一句话中说的,我一起串起来有点不好:) – Affe 2012-03-19 01:26:15

3

假设MyClass的是这样的:

public class MyClass<T>{ 
    T value; 

    public void foo(T arg){ 
    value = arg; 
    } 
} 

,然后这两个其他类:

class A{ } 

class B extends A { } 

现在想象一下,如果你这样做会发生什么:

MyClass<A> container = new MyClass<B>(); 
container.foo(new A()); 

你” d尝试将A放入B类型的字段中。您正面临的限制被认为阻止了这种情况NGS。 C#具有在IN和OUT参数仿制药方面具有极好的解决方案......

+1

'new T [2]'?!呃哦,编译器错误! – Jeffrey 2012-03-18 23:45:22

+1

@Jeffrey如果你认为一个部分/确实/编译,这个答案很容易用类比来解释这个问题。 – millimoose 2012-03-18 23:48:35

+0

是的,我得到的那部分,我不明白的是为什么第一个编译时没有错误 – rubixibuc 2012-03-18 23:51:25

4

试试这个:

MyClass<? extends Number> c = new MyClass<Double>(); 
1

任何MyClass<XXX>MyClass,但违背了你说的话,MyClass<Double>MyClass<Object>的子类。

如果您搜索删除,您可以找到更多关于它的信息,如here

+0

是不是只有类型擦除类型的原始类型?也许我误解了这个? – rubixibuc 2012-03-19 00:00:38

+0

然后什么是原始类型? – rubixibuc 2012-03-19 00:02:15

+0

我读了那篇文章和Oracle网站上的文档。如果上限是Object,则不是MyClass = MyClass ? – rubixibuc 2012-03-19 00:07:32