不兼容的类型:Class< Bar>无法转换为Class< CAP#1>其中CAP#1是新鲜类型的变量 [英] Incompatible types: Class<Bar> cannot be converted to Class<CAP#1> where CAP#1 is a fresh-type variable

查看:191
本文介绍了不兼容的类型:Class< Bar>无法转换为Class< CAP#1>其中CAP#1是新鲜类型的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我编写一些代码时,遇到了令我烦恼的事情.我在下面的代码示例中收集了两个示例.

I encountered something that bugs me when I wrote some code. I gathered the two examples in the code sample below.

cls1行使用lambda表达式,但不进行编译,而cls2行使用方法引用和编译.我知道,如果我使用的是非通用对象,那么那里就没有问题,但是在这里,我使用的是通用对象,更具体地说是通配符.

The cls1 line uses a lambda expression but doesn't compile, while the cls2 line uses a method references and compiles. I know that if I'm using non generic objects, I have no issues there, but here, I'm using generics, and, more specifically, wildcards.

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);

}

在功能上,两行都在做相同的事情.因此,我只是不了解在方法引用没有问题的情况下,导致无法使用lambda表达式的情况如何.

In functionality, both lines are doing the same. So I just don't understand what's going on under the roof that makes the use of a lambda expression fail while a method reference has no issue.

对于那些会问的人,编译时收到的错误如下:

For those who'll ask, the error received while compiling is the following:

MCVE.java:25: error: incompatible types: Class<Bar> cannot be converted to Class<CAP#1>
      .orElse(Bar.class);
                 ^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Foo from capture of ? extends Foo
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

这很简单,没有提供任何非常有用的信息.

This is rather laconic and doesn't provide any extremely useful piece of information.

另外,请注意,我已经完成了研究,这是错误的,不同于您在右侧面板上看到的类似问题"中的错误.有趣的部分是新鲜类型变量".

Also, please note that I've done my research and that this is error is not the same as in the "Similar Questions" you can see on the right panel. The interesting part here is "fresh-type variable".

推荐答案

假设您有3个课程:

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

编译器将从lambda表达式中找到:

Compiler will find from lambda expression:

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.

使用方法参考时-编译器将忽略所描述的类型推断,并使用原始的Baz类型声明,因此

When you use method reference - compiler ignores described type inference and uses original Baz type declaration, so

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

这篇关于不兼容的类型:Class&lt; Bar&gt;无法转换为Class&lt; CAP#1&gt;其中CAP#1是新鲜类型的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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