首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我不能将方法引用直接赋值给对象类型的变量?

为什么我不能将方法引用直接赋值给对象类型的变量?
EN

Stack Overflow用户
提问于 2015-03-16 16:48:01
回答 5查看 12.2K关注 0票数 22

关于java-8语法的简单问题。为什么JLS-8会限制这样的表达式:

代码语言:javascript
复制
Object of_ref = Stream::of;  // compile-time error

并且只允许这样的东西:

代码语言:javascript
复制
java.util.function.Function of_ref = Stream::of;
Object obj = of_ref; // compiles ok
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2015-03-16 16:55:47

这是因为方法引用或lambda表达式的目标类型应该是一个功能接口。仅基于此,运行时将创建一个提供给定功能接口实现的类的实例。将lambdas或方法引用视为abstract概念。将它分配给一个功能接口类型会给它一个具体的含义。

此外,特定的lambda或方法引用可以有多个功能接口作为其目标类型。例如,考虑以下lamda:

代码语言:javascript
复制
int x = 5;
FunctionalInterface func = (x) -> System.out.println(x);

这是一个Consumer of x。此外,任何具有以下签名的抽象方法的接口:

代码语言:javascript
复制
public abstract void xxx(int value);

可用作目标类型。那么,如果将lambda分配给Object类型,您希望运行时实现哪个接口?这就是为什么您必须显式地提供一个功能接口作为目标类型。

现在,一旦获得了包含实例的功能接口引用,就可以将其分配给任何超级引用(包括Object)。

票数 8
EN

Stack Overflow用户

发布于 2015-03-16 16:54:39

Object不是一个功能接口,方法引用只能分配给一个功能接口。参见例如JLS #15.13.2

如果T是函数接口类型(§9.8),则方法引用表达式在赋值上下文、调用上下文或转换上下文中与目标类型T兼容(§9.8),且表达式与从T派生的地面目标类型的函数类型一致。

票数 9
EN

Stack Overflow用户

发布于 2015-03-19 02:41:52

关键是Java中没有“函数类型”。lambda表达式本身没有"type“--它可以输入到唯一方法签名与lambda匹配的任何功能接口中。因此,lambda的类型基于其上下文提供的类型。您必须提供一个函数接口作为它获取类型的上下文。

考虑相同的问题(对于匿名类除外)是有指导意义的。尽管lambdas和匿名类之间存在实现上的差异,但在语义上,lambdas本质上等同于匿名类的子集,而lambda表达式始终可以转换为等效的匿名类创建表达式。

当你写:

代码语言:javascript
复制
Function<T, Stream<T>> of_ref = Stream::of;

它相当于使用匿名类的以下内容:

代码语言:javascript
复制
Function<T, Stream<T>> of_ref = new Function<T, Stream<T>>() {
    Stream<T> apply(T t) {
        return Stream.of(t);
    }
};

现在考虑一下

代码语言:javascript
复制
Object of_ref = Stream::of;

匿名类的等价物是什么?

代码语言:javascript
复制
Object of_ref = new [**What goes here?**]() {
    [**What method signature goes here?**] {
        return Stream.of(t);
    }
};

你知道为什么这没有意义--我们不知道用哪种类型作为匿名类的基类。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29082430

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档