下界通配符会导致 javac 出现问题,但不会导致 Eclipse [英] Lower-bounded wild card causes trouble in javac, but not Eclipse

查看:23
本文介绍了下界通配符会导致 javac 出现问题,但不会导致 Eclipse的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这段代码可以在 Eclipse 中编译,但不能在 javac 中编译:

This piece of code compiles in Eclipse but not in javac:

import java.util.function.Consumer;

public class Test {
    public static final void m1(Consumer<?> c) {
        m2(c);
    }
    private static final <T> void m2(Consumer<? super T> c) {
    }
}

javac 输出:

C:Userslukasworkspace>javac -version
javac 1.8.0_92

C:Userslukasworkspace>javac Test.java
Test.java:5: error: method m2 in class Test cannot be applied to given types;
        m2(c);
        ^
  required: Consumer<? super T>
  found: Consumer<CAP#1>
  reason: cannot infer type-variable(s) T
    (argument mismatch; Consumer<CAP#1> cannot be converted to Consumer<? super T>)
  where T is a type-variable:
    T extends Object declared in method <T>m2(Consumer<? super T>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error
----------------------------------------------------------------

哪个编译器是错误的,为什么?(此处的 Eclipse 错误报告和部分讨论)

Which compiler is wrong and why? (Eclipse bug report and parts of discussion here)

推荐答案

此代码在 JLS 8 中是合法的.javac 8 版及更早版本在处理通配符和捕获的方式上存在一些错误.从版本 9(抢先体验,我尝试了 ea-113 和更新版本)开始,javac 也接受此代码.

This code is legal wrt JLS 8. javac version 8 and earlier had several bugs in how they handle wildcards and captures. Starting with version 9 (early access, I tried version ea-113 and newer) also javac accepts this code.

要了解编译器如何根据 JLS 进行分析,必须区分通配符捕获、类型变量、推理变量等.

To understand how a compiler analyzes this according to JLS, it is essential to tell apart what are wildcard captures, type variables, inference variables and such.

c 的类型是 Consumer(javac 会写成 Consumer).此类型未知,但已修复.

The type of c is Consumer<capture#1-of ?> (javac would write Consumer<CAP#1>). This type is unknown, but fixed.

m2 的参数类型为Consumer,其中T是一个类型变量,需要通过类型推断来实例化.

The parameter of m2 has type Consumer<? super T>, where T is a type variable to be instantiated by type inference.

在类型推断期间,一个推断变量,由ecj表示为T#0,用于表示T.

During type inference an inference variable, denoted by ecj as T#0, is used to represent T.

类型推断在于确定是否可以将 T#0 实例化为任何类型而不违反任何给定的类型约束.在这种特殊情况下,我们从以下约束开始:

Type inference consists in determining, whether T#0 can be instantiated to any type without violating any given type constraints. In this particular case we start with this contraint:

⟨c → 消费者

⟨c → Consumer<? super T#0>⟩

逐步减少(通过应用 JLS 18.2):

Which is stepwise reduced (by applying JLS 18.2):

⟨Consumer→ 消费者

⟨Consumer<capture#1-of ?> → Consumer<? super T#0>⟩

⟨capture#1-of ?<= ?超级T#0⟩

⟨capture#1-of ? <= ? super T#0⟩

⟨T#0 <: capture#1-of ?⟩

⟨T#0 <: capture#1-of ?⟩

T#0 <: capture#1-of ?

T#0 <: capture#1-of ?

最后一行是类型绑定";并减少了.由于不涉及进一步的约束,解析简单地将 T#0 实例化为 capture#1-of ? 类型.

The last line is a "type bound" and reduction is done. Since no further constraints are involved, resolution trivially instantiates T#0 to the type capture#1-of ?.

通过这些步骤,类型推断已经证明 m2 适用于这个特定的调用.qed.

By these steps, type inference has proven that m2 is applicable for this particular invocation. qed.

直观地,显示的解决方案告诉我们:无论捕获可能表示什么类型,如果 T 设置为表示完全相同的类型,则不会违反任何类型约束.这是可能的,因为捕获在开始类型推断之前 是固定的.

Intuitively, the shown solution tells us: whatever type the capture may represent, if T is set to represent the exact same type, no type constraints are violated. This is possible, because the capture is fixed before starting type inference.

这篇关于下界通配符会导致 javac 出现问题,但不会导致 Eclipse的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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