tom*_*maj 24 java java-8 method-reference
例
在这个(简化的)示例中,我可以MyInterface
通过使用方法引用来创建我的对象apply
,但是直接转换不起作用.
@Test
public void testInterfaceCast(){
Function<String, Integer> func = Integer::parseInt;
MyInterface legal = func::apply; // works
MyInterface illegal = func; // error
}
public interface MyInterface extends Function<String, Integer>{}
Run Code Online (Sandbox Code Playgroud)
第二个赋值给出了编译器错误:
incompatible types: Function<String,Integer> cannot be converted to MyInterface
Run Code Online (Sandbox Code Playgroud)
这个问题
我可以做一些泛型魔法,能够投射Function<T, R>
到界面吗?
Hoo*_*pje 14
原因MyInterface illegal = func;
不起作用,是因为func
声明为类型的变量Function<String,Integer>
,而不是子类型MyInterface
.
MyInterface legal = func::apply;
作品的原因如下.你可能期望的类型fun::apply
是Function<String,Integer>
为好,但事实并非如此.类型fun::apply
取决于编译器期望的类型.由于您在赋值上下文中使用它,因此编译器需要expressen类型MyInterface
,因此在该上下文中 func::apply
是类型MyInterface
.正是由于这个原因,方法引用表达式只能出现在赋值上下文,调用上下文和转换上下文中(参见Java语言规范).
由于Function<String,Integer>
不是一个子类型MyInterface
,投掷func
到一个MyInterface
抛出ClassCastException
.因此,将a转换Function<String,Integer>
为a 的最明确方法MyInterface
是使用方法引用,就像您已经做过的那样:
MyInterface legal = func::apply;
Run Code Online (Sandbox Code Playgroud)
最重要的是,尽管所有漂亮的语法都表面上看起来如此,但Java并没有采用结构类型; Liskov 命名类型的可替代性规则与以往一样严格.在您调用的现实代码中Function.andThen
,它返回一些实例Function
,而且绝对不是实例MyInterface
.所以当你写作
MyInterface legal = func::apply;
Run Code Online (Sandbox Code Playgroud)
你会得到另一个对象,这是一个实例MyInterface
.相比之下,当你写作
MyInterface illegal = func;
Run Code Online (Sandbox Code Playgroud)
您试图将现有Function
直接实例的引用分配给illegal
,即使它在结构上与类型匹配,也会违反Liskov的可替代性.没有任何技巧可以从根本上解决这个问题; 即使Java引入了一些新的语法糖,它会使它看起来像转换,实际的语义仍然是转换(评估到另一个实例).
归档时间: |
|
查看次数: |
2092 次 |
最近记录: |