Java 不兼容类型:类<;酒吧>;无法转换为类<;第1章>;其中CAP#1是一个新类型变量

Java 不兼容类型:类<;酒吧>;无法转换为类<;第1章>;其中CAP#1是一个新类型变量,java,generics,lambda,Java,Generics,Lambda,当我写一些代码时,我遇到了一些困扰我的问题。我在下面的代码示例中收集了这两个示例 cls1行使用lambda表达式但不编译,而cls2行使用方法引用并编译。我知道如果我使用的是非泛型对象,我不会有任何问题,但在这里,我使用的是泛型,更具体地说,是通配符 import java.lang.annotation.*; import java.util.Optional; public class MCVE { static class Foo {} static class Bar ex

当我写一些代码时,我遇到了一些困扰我的问题。我在下面的代码示例中收集了这两个示例

cls1
行使用lambda表达式但不编译,而
cls2
行使用方法引用并编译。我知道如果我使用的是非泛型对象,我不会有任何问题,但在这里,我使用的是泛型,更具体地说,是通配符

import java.lang.annotation.*;
import java.util.Optional;

public class MCVE {

  static class Foo {}
  static class Bar extends Foo {}

  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.TYPE)
  static @interface Baz { Class<? extends Foo> value(); }

  @Baz(Bar.class)
  static class Quz {}

  // Lambda expression - doesn't compile
  Class<? extends Foo> cls1 = Optional.ofNullable(Quz.class.getAnnotation(Baz.class))
      .map(baz -> baz.value())
      .orElse(Bar.class);

  // Method reference - compiles
  Class<? extends Foo> cls2 = Optional.ofNullable(Quz.class.getAnnotation(Baz.class))
      .map(Baz::value)
      .orElse(Bar.class);

}
import java.lang.annotation.*;
导入java.util.Optional;
公共级MCVE{
静态类Foo{}
静态类栏扩展了Foo{}
@保留(RetentionPolicy.RUNTIME)
@目标(ElementType.TYPE)

静态@interface Baz{Class假设您有3个类:

static class Foo {}
static class Bar extends Foo {}
static class Dem extends Foo {}
编译器将从lambda表达式中找到:

var x1 = Optional.ofNullable(Quz.class.getAnnotation(Baz.class));
// typeof x1 = Optional<Baz> 

var x2 = x1.map(baz -> baz.value())
// typeof x2 = Optional<Class<T>>, where <T extends Foo> - this is the black magic you suffer with
// E.g. it can be 
// a) Optional<Class<T=Foo>> or 
// b) Optional<Class<T=Bar>> or 
// c) Optional<Class<T=Dem>>

var x3 = x2.orElse(Bar.class);
// In case (a) and (b) - this code should work, in case (c) it should fail.
// Without additional explicit hint (conversion) compiler reports about this issue.
varx1=Optional.ofNullable(Quz.class.getAnnotation(Baz.class));
//类型x1=可选
var x2=x1.map(baz->baz.value())
//typeof x2=可选,其中-这就是你所遭受的黑魔法
//它可以是
//a)可选或
//b)可选或
//c)可选
var x3=x2.orElse(巴级);
//在(a)和(b)种情况下,该代码应该可以工作,在(c)种情况下它应该失败。
//没有额外的显式提示(转换),编译器会报告此问题。
当您使用方法引用时,编译器会忽略所描述的类型推断,并使用原始的Baz类型声明,所以

.map(Baz::value) // is identical to
.map(baz -> (Class<? extends Foo>) baz.value())
.map(Baz::value)//与

.map(baz->)(ClassIn general:Java的类型系统现在几乎是一个黑匣子,关于显式类型何时必要和何时不必要的一般规则也不多。@Hosseini感谢您的链接。虽然它比我在“类似问题”中看到的更接近我的体验,它说的是赋值——我想这在这里不相关——它没有解决为什么lambda不合适的问题,但是方法引用可以。在eclipse中,我在这两种情况下都会出错。将
map
的结果赋值给
Optional@JornVernee我也这么做了;不过,如果你手动编译,然后cls2行不会给出错误。可能是Eclipse中的错误。这个解释让我感到困惑,这就是为什么我还没有接受。你的
Bar
Dem
类之间绝对没有区别,但是你说它不同:“在案例(a)和(b)中”-这段代码应该可以工作,以防(c)失败。“这太不一致了,我就是无法绕开它来正确理解。也许你在什么地方有输入错误?当t=Der时,你有typeof x2=Optional,所以你不能应用orElse(Bar.class)to it-Der和Bar不兼容。您不能将Der对象强制转换为Bar,反之亦然。这只是一个显示编译器问题的理论示例。好的,您的意图更清楚,我理解您的意思。感谢您所做的一切:)