Java 为什么类型参数比方法参数强

Java 为什么类型参数比方法参数强,java,generics,lambda,type-inference,Java,Generics,Lambda,Type Inference,为什么 生成所需的编译时错误: 类型BuilderExample.MyInterface中的getLength()的类型很长,这与描述符的返回类型:String不兼容 当使用方法with()时,不起作用 完整示例: import java.util.function.function; 公共类SO58376589{ 公共静态类生成器{ 带有x(F getter,R returnValue)的公共生成器{ 归还这个; } 具有(函数getter,R returnValue)的公共生成器{ 归还这个

为什么

生成所需的编译时错误:

类型BuilderExample.MyInterface中的getLength()的类型很长,这与描述符的返回类型:String不兼容

当使用方法
with()时,
不起作用

完整示例:
import java.util.function.function;
公共类SO58376589{
公共静态类生成器{
带有x(F getter,R returnValue)的公共生成器{
归还这个;
}
具有(函数getter,R returnValue)的公共生成器{
归还这个;
}
}
静态接口MyInterface{
公共长getLength();
}
公共静态void main(字符串[]args){
生成器b=新生成器();
函数getter=MyInterface::getLength;
b、 含(吸气剂,2L);
b、 带有(MyInterface::getLength,2L);
b、 用x(吸气剂,2L);
b、 withX(MyInterface::getLength,2L);
b、 使用(getter,“No NUMBER”);//错误
b、 使用(MyInterface::getLength,“No NUMBER”);//无错误!!
b、 withX(getter,“No NUMBER”);//错误
b、 withX(MyInterface::getLength,“无编号”);//错误!!!
}
}
javac SO58376589.java

SO58376589.java:32:error:类生成器中的方法无法应用于给定类型;
b、 使用(getter,“No NUMBER”);//错误
^
必需:功能,R
找到:函数,字符串
原因:推理变量R的边界不兼容
平等约束:长
下限:字符串
其中R,T是类型变量:
R使用(函数,R)扩展方法中声明的对象
T扩展类生成器中声明的对象
java:34:error:class Builder中的withX方法无法应用于给定类型;
b、 使用x(getter,“No NUMBER”);//错误
^
所需:F、R
找到:函数,字符串
原因:推理变量R的边界不兼容
平等约束:长
下限:字符串
其中F、R、T是类型变量:
F用x(F,R)扩展方法中声明的函数
R用x(F,R)扩展方法中声明的对象
T扩展类生成器中声明的对象
SO58376589.java:35:错误:不兼容的类型:无法推断类型变量R,F
b、 withX(MyInterface::getLength,“无编号”);//错误
^
(参数不匹配;方法引用中的返回类型错误)
Long(不能转换为字符串)
其中R、F、T是类型变量:
R用x(F,R)扩展方法中声明的对象
F用x(F,R)扩展方法中声明的函数
T扩展类生成器中声明的对象
3个错误
扩展示例 下面的示例显示了方法和类型参数对供应商的不同行为。此外,它还显示了类型参数与使用者行为的差异。它表明,无论是方法参数的消费者还是供应商,都没有区别

SO58376589.java:32: error: method with in class Builder<T> cannot be applied to given types;
    b.with(getter, "No NUMBER"); // error
     ^
  required: Function<MyInterface,R>,R
  found: Function<MyInterface,Long>,String
  reason: inference variable R has incompatible bounds
    equality constraints: Long
    lower bounds: String
  where R,T are type-variables:
    R extends Object declared in method <R>with(Function<T,R>,R)
    T extends Object declared in class Builder
SO58376589.java:34: error: method withX in class Builder<T> cannot be applied to given types;
    b.withX(getter, "No NUMBER"); // error
     ^
  required: F,R
  found: Function<MyInterface,Long>,String
  reason: inference variable R has incompatible bounds
    equality constraints: Long
    lower bounds: String
  where F,R,T are type-variables:
    F extends Function<MyInterface,R> declared in method <R,F>withX(F,R)
    R extends Object declared in method <R,F>withX(F,R)
    T extends Object declared in class Builder
SO58376589.java:35: error: incompatible types: cannot infer type-variable(s) R,F
    b.withX(MyInterface::getLength, "No NUMBER"); // error
           ^
    (argument mismatch; bad return type in method reference
      Long cannot be converted to String)
  where R,F,T are type-variables:
    R extends Object declared in method <R,F>withX(F,R)
    F extends Function<T,R> declared in method <R,F>withX(F,R)
    T extends Object declared in class Builder
3 errors
import java.util.function.Consumer;
导入java.util.function.Supplier;
接口类型推断{
Number getNumber();
无效设置编号(编号n);
@功能接口
接口方法{
类型推断be(R);
}
//供应商:
R letBe(供应商,R值);
R letBeX(F供应商,R值);
方法let(Supplier);//返回(x)->this;
//消费者:
R lettBe(消费者供应商,R值);
R lettBeX(F供应商,R值);
方法(消费者);
公用静态空干管(t型){
t、 letBe(t::getNumber,(Number)2);//编译:-)
t、 lettBe(t::setNumber,(Number)2);//编译:-)
t、 letBe(t::getNumber,2);//编译:-)
t、 lettBe(t::setNumber,2);//编译:-)
t、 letBe(t::getNumber,“NaN”);/!!编译:-(
t、 lettBe(t::setNumber,“NaN”);//不编译:-)
t、 letBeX(t::getNumber,(Number)2);//编译:-)
t、 lettBeX(t::setNumber,(Number)2);//编译:-)
t、 letBeX(t::getNumber,2);/!!!不编译:-(
t、 lettBeX(t::setNumber,2);//编译:-)
t、 letBeX(t::getNumber,“NaN”);//不编译:-)
t、 lettBeX(t::setNumber,“NaN”);//不编译:-)
t、 let(t::getNumber).be(2);//编译:-)
t、 lett(t::setNumber).be(2);//编译:-)
t、 let(t::getNumber).be(“NaN”);//不编译:-)
t、 lett(t::setNumber).be(“NaN”);//不编译:-)
}
}

这是一个非常有趣的问题。恐怕答案很复杂

tl;博士 解决差异需要相当深入地阅读Java,但基本上可以归结为:

  • 在所有其他条件相同的情况下,编译器推断出它所能推断出的最具体的类型
  • 然而,如果它能够找到满足所有需求的类型参数的替换,那么编译将成功,不管替换结果如何模糊
  • 对于带有的
    ,有一个(公认模糊的)替代,它满足
    R
    的所有要求:
    可序列化
  • 对于
    with x
    ,附加类型参数
    F
    的引入迫使编译器首先解析
    R
    ,而不考虑约束
    F extends函数
    R
    解析为(更具体的)
    字符串
    ,这意味着
    F
    的推断失败
最后一点是最重要的,也是最重要的。我想不出更简洁的措辞了,所以如果你想了解更多细节,我建议你阅读下面的完整解释

这是故意的行为吗? 我要孤注一掷,说不

我并不是说规范中有缺陷,更重要的是(在
with x
的情况下)语言设计者举手说“有些情况下类型推断太难了,所以我们会失败”。尽管编译器对于<>代码> x < /C> >的行为似乎是您想要的,但我认为这是当前规范的附带副作用,而不是。
public <R> Builder<T> with(Function<T, R> getter, R returnValue) {...}
.withX(MyInterface::getLength, "I am not a Long")
import java.util.function.Function;

public class SO58376589 {
  public static class Builder<T> {
    public <R, F extends Function<T, R>> Builder<T> withX(F getter, R returnValue) {
      return this;
    }

    public <R> Builder<T> with(Function<T, R> getter, R returnValue) {
      return this;
    }

  }

  static interface MyInterface {
    public Long getLength();
  }

  public static void main(String[] args) {
    Builder<MyInterface> b = new Builder<MyInterface>();
    Function<MyInterface, Long> getter = MyInterface::getLength;
    b.with(getter, 2L);
    b.with(MyInterface::getLength, 2L);
    b.withX(getter, 2L);
    b.withX(MyInterface::getLength, 2L);
    b.with(getter, "No NUMBER"); // error
    b.with(MyInterface::getLength, "No NUMBER"); // NO ERROR !!
    b.withX(getter, "No NUMBER"); // error
    b.withX(MyInterface::getLength, "No NUMBER"); // error !!!
  }
}
SO58376589.java:32: error: method with in class Builder<T> cannot be applied to given types;
    b.with(getter, "No NUMBER"); // error
     ^
  required: Function<MyInterface,R>,R
  found: Function<MyInterface,Long>,String
  reason: inference variable R has incompatible bounds
    equality constraints: Long
    lower bounds: String
  where R,T are type-variables:
    R extends Object declared in method <R>with(Function<T,R>,R)
    T extends Object declared in class Builder
SO58376589.java:34: error: method withX in class Builder<T> cannot be applied to given types;
    b.withX(getter, "No NUMBER"); // error
     ^
  required: F,R
  found: Function<MyInterface,Long>,String
  reason: inference variable R has incompatible bounds
    equality constraints: Long
    lower bounds: String
  where F,R,T are type-variables:
    F extends Function<MyInterface,R> declared in method <R,F>withX(F,R)
    R extends Object declared in method <R,F>withX(F,R)
    T extends Object declared in class Builder
SO58376589.java:35: error: incompatible types: cannot infer type-variable(s) R,F
    b.withX(MyInterface::getLength, "No NUMBER"); // error
           ^
    (argument mismatch; bad return type in method reference
      Long cannot be converted to String)
  where R,F,T are type-variables:
    R extends Object declared in method <R,F>withX(F,R)
    F extends Function<T,R> declared in method <R,F>withX(F,R)
    T extends Object declared in class Builder
3 errors
import java.util.function.Consumer;
import java.util.function.Supplier;
interface TypeInference {

  Number getNumber();

  void setNumber(Number n);

  @FunctionalInterface
  interface Method<R> {
    TypeInference be(R r);
  }

  //Supplier:
  <R> R letBe(Supplier<R> supplier, R value);
  <R, F extends Supplier<R>> R letBeX(F supplier, R value);
  <R> Method<R> let(Supplier<R> supplier);  // return (x) -> this;

  //Consumer:
  <R> R lettBe(Consumer<R> supplier, R value);
  <R, F extends Consumer<R>> R lettBeX(F supplier, R value);
  <R> Method<R> lett(Consumer<R> consumer);


  public static void main(TypeInference t) {
    t.letBe(t::getNumber, (Number) 2); // Compiles :-)
    t.lettBe(t::setNumber, (Number) 2); // Compiles :-)
    t.letBe(t::getNumber, 2); // Compiles :-)
    t.lettBe(t::setNumber, 2); // Compiles :-)
    t.letBe(t::getNumber, "NaN"); // !!!! Compiles :-(
    t.lettBe(t::setNumber, "NaN"); // Does not compile :-)

    t.letBeX(t::getNumber, (Number) 2); // Compiles :-)
    t.lettBeX(t::setNumber, (Number) 2); // Compiles :-)
    t.letBeX(t::getNumber, 2); // !!! Does not compile  :-(
    t.lettBeX(t::setNumber, 2); // Compiles :-)
    t.letBeX(t::getNumber, "NaN"); // Does not compile :-)
    t.lettBeX(t::setNumber, "NaN"); // Does not compile :-)

    t.let(t::getNumber).be(2); // Compiles :-)
    t.lett(t::setNumber).be(2); // Compiles :-)
    t.let(t::getNumber).be("NaN"); // Does not compile :-)
    t.lett(t::setNumber).be("NaN"); // Does not compile :-)
  }
}
static Runnable x = () -> System.out.println();
public class Builder<T> {

    public final class With<R> {
        private final Function<T,R> method;

        private With(Function<T,R> method) {
            this.method = method;
        }

        public Builder<T> of(R value) {
            // TODO: Body of your old 'with' method goes here
            return Builder.this;
        }
    }

    public <R> With<R> with(Function<T,R> method) {
        return new With<>(method);
    }

}

b.with(MyInterface::getLong).of(1L); // Compiles
b.with(MyInterface::getLong).of("Not a long"); // Compiler error