为什么使用原始“int”的“Comparator”在这段代码中起作用?如果自动装箱,什么时候发生?

发布于 2025-01-16 20:13:53 字数 1363 浏览 3 评论 0原文

我将此代码编写为另一个问题的解决方案

record Person( String name , int age ) { }
List < Person > persons =
        List.of(
                new Person( "Alice" , 52 ) ,
                new Person( "Bob" , 23 ) ,
                new Person( "Carol" , 39 )
        );

List < Person > sorted =
        persons
                .stream()
                .sorted( Comparator.comparing( Person :: age ) )
                .toList();

此代码在 Java 17

persons.toString() = [Person[name=Alice,age=52],Person[name=Bob,age=23],Person[name=Carol,age=39]]

sorted.toString() = [人物[姓名=鲍勃,年龄=23],人物[姓名=卡罗尔,年龄=39],人物[姓名=爱丽丝,年龄=52]]

经过进一步思考,我对这段代码的工作原理感到惊讶。我将 记录 上的访问器方法(“getter”)的方法引用传递给 Comparator.comparing 调用。

Comparator.comparing( Person :: age )

…但是age成员字段和该方法的返回类型都是int基元,而不是对象。

I wrote this code as a solution on another Question:

record Person( String name , int age ) { }
List < Person > persons =
        List.of(
                new Person( "Alice" , 52 ) ,
                new Person( "Bob" , 23 ) ,
                new Person( "Carol" , 39 )
        );

List < Person > sorted =
        persons
                .stream()
                .sorted( Comparator.comparing( Person :: age ) )
                .toList();

This code runs successfully on Java 17.

persons.toString() = [Person[name=Alice, age=52], Person[name=Bob, age=23], Person[name=Carol, age=39]]

sorted.toString() = [Person[name=Bob, age=23], Person[name=Carol, age=39], Person[name=Alice, age=52]]

Upon further thought, I am surprised this code works. I pass a method reference for the accessor method (“getter”) on the record to Comparator.comparing call.

Comparator.comparing( Person :: age )

… but age member field, and the return type of this method, are both int primitive, not an object.

???? This leaves me puzzled as to why this works, because I would think the comparator requires objects, not primitives.

Is there some auto-boxing at play here? If so, exactly where? What triggers the compiler or runtime to perform auto-boxing in this code?

I am hoping for a narrow and precise answer rather than same hand-waving. The hand-waving was already done when I authored the code! So, now, I am not asking out of practicality, as clearly the code is intuitive and the code works. The language-lawyer tag is indeed appropriate here, as I am asking about the “intricacies of formal or authoritative specifications of programming languages”.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆蝶 2025-01-23 20:13:53

我将留给读者一个练习,即 Person::age 的解析过程识别潜在适用的方法 intage()作为精确方法引用表达式。确定目标方法后,来自 JLS 15.13.2

如果以下两个条件都成立,则方法引用表达式与函数类型一致

  • 函数类型标识与引用相对应的单个编译时声明。
  • 以下情况之一是正确的:[...]
    • 函数类型的结果是 R,将捕获转换(第 5.1.10 节)应用于所选编译时声明的调用类型(第 15.12.2.6 节)的返回类型的结果是 R'(其中 R 是可用于推断 R' 的目标类型,并且 R 和 R' 都不是 void,并且 R' 在赋值上下文中与 R 兼容。

这里的函数类型是FunctionT 显然是 Person,而 comparing 的签名需要一些 U extends Comparable

int 类型与赋值上下文中的Integer 兼容,随后也与 Comparable 兼容( JLS 5.2):

赋值上下文允许使用以下之一:[...]

  • 先进行装箱转换,然后再进行扩大参考转换

I'll leave as an exercise for the reader that the resolution process for Person::age identifies the potentially-applicable method int age() as an exact method reference expression. Having identified the target method, from JLS 15.13.2:

A method reference expression is congruent with a function type if both of the following are true:

  • The function type identifies a single compile-time declaration corresponding to the reference.
  • One of the following is true: […]
    • The result of the function type is R, and the result of applying capture conversion (§5.1.10) to the return type of the invocation type (§15.12.2.6) of the chosen compile-time declaration is R' (where R is the target type that may be used to infer R'), and neither R nor R' is void, and R' is compatible with R in an assignment context.

The function type here is Function<? super T, ? extends U>. T is clearly Person, and the signature of comparing requires some U extends Comparable<? super U>.

The type int is compatible with Integer in an assignment context and then subsequently also compatible with Comparable<Integer> (JLS 5.2):

Assignment contexts allow the use of one of the following: […]

  • a boxing conversion followed by a widening reference conversion
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文