为什么涉及通配符的此分配在Java中合法? [英] Why is this assignment involving wildcards legal in Java?

查看:42
本文介绍了为什么涉及通配符的此分配在Java中合法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于通配符的大多数问题都想知道为什么编译器拒绝明智的选择.我的问题是相反的.为什么编译器接受以下程序?

Most questions about wildcards want to know why something sensible is rejected by the compiler. My question is the opposite. Why is the following program accepted by the compiler?

void test(List<? extends Number> g1, List<? extends Number> g2)
{
    g1 = g2;
}

我试图从Java语言规范中对此进行解释,但是我没有找到答案.从Java泛型和通配符的各种描述中,我得到的印象是,通配符的每次使用都被捕获为一种全新的类型,但显然不在这里.我尚未发现允许此分配执行任何令人讨厌的行为,但仍然看起来错误".

I tried to explain this from the Java Language Specification, but I have not found the answer. I had the impression from various descriptions of Java generics and wildcards that each use of a wildcard is captured as a completely new type, but apparently not here. I have not found any nasty behavior that follows from this assignment being allowed, but it still seems "wrong".

推荐答案

当我面对这些问题时,我会以略有不同的方式来解决这个问题.

When I face these questions, I approach this in a slightly different manner.

首先,每个通配符均由 javac 进行捕获无处不在.用简单的英语来说:每次 javac "sees"一个<通配符,它将进行转换(这将几乎准确,您将进一步看到).具体来说,假设我们有以下内容:

First of all, every single wildcard is captured, everywhere, by javac. In plain english: every time javac "sees" a wildcard it is going to transform that (this is almost accurate as you will see further). Specifically, let's say we have this:

List<? extends Number> list;

javac 将转换为:

List<X1> list

其中 X1< ;:数字,其中<:表示它是的子类型,例如: X1是扩展Number的未知类型.每次发生都会发生这种情况.在某些情况下,一开始它可能很奇怪:

where X1 <: Number, where <: means it is a subtype of, as such : X1 is an unknown type that extends Number. This will happen for every single occurrence. And it might be very weird, at first, in some scenarios:

public static void main(String[] args) {
    List<?> l = new ArrayList<String>();
    one(l);
    two(l, l); // fails
}

public static <T> void one(List<T> single){

}

public static <T> void two(List<T> left, List<T> right){

}

捕获转换分别应用于每个 List ,就像这样:

capture conversion was applied individually to each List, it's like this happened:

two(List<X1>, List<X2>)


现在,为什么您的示例被接受了,真是太有趣了,恕我直言.您知道应用了捕获转换,但是根据 JLS ,它是

如果表达式名称是显示在左侧"的变量,则其类型不进行捕获转换.

If the expression name is a variable that appears "on the left hand side", its type is not subject to capture conversion.

这就像说,只有是捕获转换的,而不是变量.

It's like saying that only values are capture converted, not variables.

所以在这种情况下:

g1 = g2;

g1 尚未捕获转换,而 g2 已捕获.就像这样做:

g1 has not been capture converted, while g2 has. It's like doing:

List<? extends Number> g1 = List<X1> (g2) // pseudo-code

我们知道 X1< ;: Number ,因此,这样的 List< X1> List<的子类型?扩展Number> ,因此分配有效.

We know that X1 <: Number so, as such List<X1> is a subtype of List<? extends Number>, so the assignment works.

即使您更改了?将Number 扩展到?(这不再是有界通配符),仍然可以使用.

Even if you change ? extends Number to ? (this is not a bounded wildcard anymore), this would still work.

这篇关于为什么涉及通配符的此分配在Java中合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆