【问题标题】:Raw types and Generics -- Java [duplicate]原始类型和泛型——Java [重复]
【发布时间】:2012-04-03 12:49:36
【问题描述】:

可能重复:
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

使用原始类型,您可以轻松说出这样的话。

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

MyClass c = new MyClass<Double>();

[...]

但这是不允许的

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

我不明白这是为什么。我的书告诉我为什么第二个不起作用,因为您不能将整数添加到 MyClass&lt;Double&gt;。它没有解释为什么 MyClass&lt;Double&gt;MyClass&lt;Object&gt; 的子类(或等效的原始类型形式),因为 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
}
}

我的观点是,为什么声明 Generic 就像它最终被视为上限一样重要?

【问题讨论】:

  • 我的问题是相反的,我在问为什么你可以从一个子类分配一个原始类型
  • 该问题的前提也是错误的,因为类型擦除只关心上限是否与方法一起使用,并使用类型检查强制转换。至少这是我读过的内容

标签: java generics


【解决方案1】:

假设 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());

您会尝试将 A 放入 B 类型的字段中。您面临的限制被认为可以防止此类事情发生。 C# 在泛型的输入和输出参数方面有一个很好的解决方案......

【讨论】:

  • new T[2]?!哦哦,编译器错误!
  • @Jeffrey 如果您假设一部分 /does/ 编译,则此答案通过类比非常简洁地说明了问题。
  • 是的,我得到的那部分,我不明白的是为什么第一个编译没有错误
  • 通过类型擦除,该函数将所有内容都视为对象,然后在必须时进行强制转换
  • 但是您假设该数组是 double 类型,在这种情况下,它在编译时是 Object 类型。所有方法调用都基于上限进行测试。因此,如果在这种情况下它适用于 Object 的默认值,它将适用于任何 Object 的子类
【解决方案2】:

试试这个:

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

【讨论】:

    【解决方案3】:

    任何MyClass&lt;XXX&gt; 都是MyClass,但与您所说的相反,MyClass&lt;Double&gt; 不是MyClass&lt;Object&gt; 的子类。

    如果您搜索擦除,您可以找到更多相关信息,例如here

    【讨论】:

    • 不是原始类型只是类型擦除的类型吗?也许我误解了这个?
    • 那么什么是原始类型?
    • 我阅读了上面所说的内容以及 oracle 网站上的文档。如果上限是 Object is not MyClass = MyClass?
    • @rubixibuc 看起来你找到了答案。如果您想深入了解,我建议您阅读有关原始类型的 Java Language Specification
    【解决方案4】:

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

    原始类型的行为方式和参数化类型的行为方式之间的任何比较从根本上来说都是虚假的。设计的目的不是将原始类型视为声明参数的“替代方案”。使用原始类型的新代码是不正确的代码。编译它是合法的,这样旧代码仍然可以工作。

    我的观点是,为什么将 Generic 声明为重要 如果它最终被视为上限?

    因为泛型的全部意义在于防止 ClassCastException。当某人(例如,某人将对象从列表中取回并将其分配给他们期望的特定类型时)被视为实际声明的类型。编译器承诺它会保证这会成功,因此它必须限制进出的内容。

    【讨论】:

    • 在做了一些深入的研究之后,我正在回答我自己的问题,而你完美地回答了它。是的,这是有道理的,如果返回类型不同意会发生什么。感谢您澄清这一点。
    • 我唯一不同意的是它被视为声明的类型而不是上限。当方法或类编译时,我知道发生的唯一转换返回到函数返回时的参数化类型。由于类型擦除,其他所有内容都隐式转换为上限并在方法中如此处理。请让我知道我是否正确。
    • 是的,这就是我在连串句子中想要表达的意思,但我串起来有点糟糕:)
    猜你喜欢
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多