首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于方法引用的过载解析和基元类型的函数接口专门化

基于方法引用的过载解析和基元类型的函数接口专门化
EN

Stack Overflow用户
提问于 2017-08-25 09:18:09
回答 1查看 210关注 0票数 6

假设我们有一个类和一个重载函数:

代码语言:javascript
复制
public class Main {
    static final class A {
    }

    public static String g(ToIntFunction<? extends A> f) {
        return null;
    }

    public static String g(ToDoubleFunction<? extends A> f) {
        return null;
    }
}

我想用方法引用来调用g,该函数的类型为A、->、int:

代码语言:javascript
复制
public class Main {
    static final class A {
    }

    public static String g(ToIntFunction<? extends A> f) {
        return null;
    }

    public static String g(ToDoubleFunction<? extends A> f) {
        return null;
    }

    private static int toInt(A x) {
        return 2;
    }

    public static void main(String[] args) {
        ToIntFunction<? extends A> f1 = Main::toInt;
        ToDoubleFunction<? extends A> f2 = Main::toInt;

        g(Main::toInt);
    }
}

这适用于javac,但不适用于eclipse。我向ecj提交了一个bug报告,但我不确定这是ecj还是javac bug,并试图遵循重载解决算法来解决它。我的感觉是,代码应该被接受,因为从直觉上看,ToIntFunctionToDoubleFunction更适合toInt。然而,我对JLS的解读是,它应该被拒绝,因为没有更具体的理由。

我必须承认,我有点迷失在JLS规范,并希望得到一些帮助。我首先想要计算Main::double2int的类型,所以我查看了15.13.2.方法引用的类型。它没有定义类型,但定义了类型在不同上下文中兼容的时间:

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

地面类型为ToIntFunction<A>ToDoubleFunction<A>toInt返回一个int,它的赋值与double兼容,因此我的结论是,方法引用在调用上下文中与ToIntFunction<? extends A>ToDoubleFunction<? extends A>是不可见的。通过对主函数中接受的ToIntFunction<? extends A>ToDoubleFunction<? extends A>两种方法的参考,可以验证这一点。

然后,我研究了重载解析,发现了15.12.2.5选择最具体的方法,它有一个特殊的情况,用于方法引用,以决定ToIntFunctionToDoubleFunction的两个重载中哪个对编译时声明A -> int的参数Main::toInt更为具体。

函数接口类型S比表达式e的函数接口类型T更具体,如果T不是S的子类型,下面的一个是正确的(其中U1 .Uk和R1是捕获S和V1的函数类型的参数类型和返回类型。Vk和R2是T函数类型的参数类型和返回类型: ..。 如果e是一个精确的方法引用表达式(第15.13.1节),那么对于所有的i (1≤i≤k),Ui与Vi是相同的,并且ii)下列一项是正确的: R2是无效的。 R1 <::R2. R1是一个基本类型,R2是一个引用类型,方法引用的编译时声明有一个返回类型,它是一个基本类型。 R1是一个引用类型,R2是一个基本类型,方法引用的编译时声明有一个返回类型,它是一个引用类型。

第一个条件显然不匹配,因为R1和R2不是无效的。

这两个接口ToIntFunctionToDoubleFunction仅在它们的返回类型上有区别,它们是基本类型doubleint。对于基本类型,子句"R1 <:R2“是根据类型的大小在4.10.1中定义的。doubleint之间没有任何关系,因此本例没有定义哪种类型更具体。

最后两个点也不适合,因为这两个函数接口中没有一个具有引用类型的返回值。

当两个函数接口返回原语并且代码应该被拒绝为模棱两可时,似乎没有规则。但是,javac接受代码,我希望它能够这样做。所以我想知道这是否是JLS中的一个缺失点。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-26 02:58:58

对于基本类型,子句"R1 <:R2“是根据类型的大小在4.10.1中定义的。double和int之间没有任何关系,因此这种情况没有定义哪种类型更具体。

事实并非如此;事实上,doubleint的超级类型。

第4.10段

一种类型的超型是由自反型和传递闭包在直接超型关系S >₁ T上得到的,这种关系是由本节后面给出的规则定义的。我们编写S :> T来表示ST之间的超级类型关系。

第4.10.1段

以下规则定义了基元类型之间的直接超级类型关系: double >₁ float float >₁ long long >₁ int

超型关系是直接超型关系的自反闭包和传递闭包,它意味着(double >₁ float) ∧ (float >₁ long) ∧ (long >₁ int)遵循double :> int

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

https://stackoverflow.com/questions/45878208

复制
相关文章

相似问题

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