为什么要对 lambda 输入参数执行强制转换?

Joh*_*yer 5 java generics lambda

我接受,由于下限通配符,这个谓词不应该接受String没有显式转换的超类。[ 1 , 2 ] 这个问题是关于 lambda 参数列表中的类型安全实施。鉴于第二个块编译失败,为什么第一个块可以在没有警告的情况下编译?似乎在第一种情况下,尽管 lambda 的参数声明CharSequence被强制转换String为满足谓词的边界约束。

    Predicate<? super String> predicate1 = (CharSequence c)
       -> c.toString().length() > 2 ;
    System.out.println(predicate1.test("foo"));                 // compiles

Run Code Online (Sandbox Code Playgroud)
    Predicate<? super String> predicate2 = (CharSequence c)
       -> c.toString().length() > 2 ;
    System.out.println(predicate2.test((CharSequence)"foo"));  // capture error

Run Code Online (Sandbox Code Playgroud)
error: method test in interface Predicate<T> cannot be applied to given types;
    out.println(predicate2.test((CharSequence)"foo")); 
                          ^
  required: CAP#1
  found: CharSequence
  reason: argument mismatch; CharSequence cannot be converted to CAP#1
  where T is a type-variable:
    T extends Object declared in interface Predicate
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object super: String from capture of ? super String

Run Code Online (Sandbox Code Playgroud)

感谢您在这方面所做的工作。问题似乎是假设 lambda 和通用进程将强制使用CharSequence. 但是,现在很明显String可以在没有编译器错误的情况下提交给 lambda,所以在第一种情况下发生了什么,并且 aString被提交给两个进程。泛型过程忽略 lambda 的内容也就不足为奇了。

And*_*ner 4

Predicate<? super String> predicate2 = (CharSequence c)
   -> c.toString().length() > 2 ;
System.out.println(predicate2.test((CharSequence)"foo"));  // capture error
Run Code Online (Sandbox Code Playgroud)

问题是predicate2说它是会接受 a 的东西String;你试图将它传递给CharSequence.

如果将变量的声明更改为

Predicate<? super CharSequence> predicate2
Run Code Online (Sandbox Code Playgroud)

然后就可以了。

这不起作用的原因是您可能将 a 传递MyCharSequence implements CharSequence给谓词:

System.out.println(predicate2.test((CharSequence)new MyCharSequence()));
Run Code Online (Sandbox Code Playgroud)

这不应该被接受,因为变量的类型predicate2表明它应该只期望给出一个 的实例String。编译器只将实际参数的类型视为CharSequence,因此它无法区分“这是一个String”(可以)和“这是一个MyCharSequence”(不行)。

  • @用户,您不知道类型是什么,但您知道它是“String”(或“String”本身)的某种超类型,因此您可以安全地将“String”传递给它。 (2认同)