Java 为什么类型参数比方法参数强
为什么 生成所需的编译时错误: 类型BuilderExample.MyInterface中的getLength()的类型很长,这与描述符的返回类型:String不兼容 当使用方法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)的公共生成器{ 归还这个
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