为什么在Java泛型中这个赋值是非法的?

huangapple go评论71阅读模式
英文:

Why is this assignment illegal in Java generics?

问题

我确信我可能在这里漏掉了一些相当明显的东西,但是否有一个原因:

ArrayList<? extends Number> list = new ArrayList<Number>();

被允许,但是:

ArrayList<T extends Number> list = new ArrayList<Number>();

却不被允许?

英文:

I'm sure I'm probably missing something fairly obvious here, but is there a reason why:

ArrayList&lt;? extends Number&gt; list = new ArrayList&lt;Number&gt;();

is allowed, but:

ArrayList&lt;T extends Number&gt; list = new ArrayList&lt;Number&gt;();

is not?

答案1

得分: 4

因为,在这里:

ArrayList<? extends Number> list = new ArrayList<Number>(); //OK

你正在使用 上界通配符 <? extends Number> 来定义类型为 ArrayList 的具体对象。

通配符的类型将匹配任何 Number 的子类型,这意味着你可以将任何用 任何 扩展了 Number 的类型来专门化的 ArrayList 分配给你的 list 变量:

list = new ArrayList<Float>(); //将正常工作
list = new ArrayList<Double>(); //将正常工作
list = new ArrayList<String>(); //不会工作,因为 String 不扩展 Number

唯一的注意点是捕获问题。你将无法在列表中添加继承自 Number 的实例。


然而,在这个例子中:

ArrayList<T extends Number> list = new ArrayList<Number>(); //语法错误

你的对象声明中存在语法错误。你正在使用有界类型参数来声明变量;然而,有界类型参数用于定义泛型类/类型或泛型方法。

类型参数 T,或者任何(最好是大写)字母,用于在定义类(或方法)时声明泛型类型参数

例如,在此定义中,你的上界泛型类型:

public class YourClass<T extends Number> {
    // ...
}

将在运行时成为一个真正的类型,当你通过提供一些真正的类型作为泛型类型参数来声明你的 YourClass 类型时,就像这样:

YourClass<Integer> ints; //将正常工作
YourClass<Double> doubles; //将正常工作
YourClass<Float> floats; //将正常工作
YourClass<String> strings; //不会工作,因为 String 不扩展 Number

注意,这里同样,T extends Number 匹配任何扩展了 Number 的类型。

英文:

Because, with:

ArrayList&lt;? extends Number&gt; list = new ArrayList&lt;Number&gt;(); //OK

you are defining the concrete object of type ArrayList generalized with upper bounded wildcard &lt;? extends Number&gt;.

Type of your wildcard will match any sub-type of Number, which means that you can assign to your list variable, any ArrayList specialized with any type which extends Number:

list = new ArrayList&lt;Float&gt;(); //will work fine
list = new ArrayList&lt;Double&gt;(); //will work fine
list = new ArrayList&lt;String&gt;(); //will NOT work as String does not extend Number

The only caveat is the Capture Problem. You won't be able to add Number extender instances in your list.


In here, however:

ArrayList&lt;T extends Number&gt; list = new ArrayList&lt;Number&gt;(); //Syntax error

you have a syntax error in your object declaration. You are using bounded type parameter to declare your variable; however, bounded type parameter is used to define a generic class/type or generic method.

Type parameter T, or any (preferably capital) letter, is used to declare a generic type parameter when you define your class (or method).

For example, your upper-bounded generic type in this definition:

public class YourClass&lt;T extends Number&gt; {
....
}

will become a real type, at run-time, when you will declare your YourClass type by providing some real type, as a generic type argument, like this:

YourClass&lt;Integer&gt; ints; //will work fine
YourClass&lt;Double&gt; doubles; //will work fine
YourClass&lt;Float&gt; floats; //will work fine
YourClass&lt;String&gt; strings; //will NOT work, as String does not extend Number

Pay attention, that here as well, T extends Number matches any type that extends Number.

答案2

得分: 0

如果您想要使用像 T 这样的通用类型类,您需要在您的类中明确声明它。您可以在这里找到官方文档。

如果您想要使用未知通配符类,您可以根据这里的说明在您的代码中自由使用它。

无论如何,您可以在这里找到一个类似的问题。

英文:

If you want to use a generic type class like T you need to explicitly declare it in your class. Here you can find official documentation.

If you want to use an unknownk wildcard class instead, you can use if freely in you code as mentiond here

Anyway, you can find a similar question here

答案3

得分: -2

以下是翻译好的部分:

/**
 * 泛型版本的Box类。
 * @param <T> 被封装的值的类型
 */
public class Box<T> {
    // T代表“类型”
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

因此,你可以使用类似这样的语法来创建一个ArrayList:ArrayList<T> arr = new ArrayList<T>()

来源:https://docs.oracle.com/javase/tutorial/java/generics/types.html

英文:

generic class in java should look like this

/**
 * Generic version of the Box class.
 * @param &lt;T&gt; the type of the value being boxed
 */
public class Box&lt;T&gt; {
    // T stands for &quot;Type&quot;
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

so you can use something like ArrayList&lt;T&gt; arr = new ArrayList&lt;T&gt;()

source: https://docs.oracle.com/javase/tutorial/java/generics/types.html

huangapple
  • 本文由 发表于 2020年9月3日 01:27:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63710691.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定