【问题标题】:Behavior of Functional Interface and Method Reference功能接口的行为和方法参考
【发布时间】:2015-10-07 21:12:00
【问题描述】:

当属于变量的方法的引用被销毁时会发生什么?

public class Hey{
    public double bar;

    public Hey(){
        bar = 2.0d;
    }

    public double square(double num){
        return Math.pow(num , bar);
    }
}

Function<Double, Double> square;
whatsGonnaHappen: {
    Hey hey = new Hey();
    square = hey::square;
}//is hey still kept around because its method is being referenced?

double ans = square.apply(23d);

【问题讨论】:

  • 你试过在 square 之后调用方法吗?为什么会消失?
  • 你指的是什么功能接口,顺便说一句?
  • Function 接口位于 java.util.function @Stultuske
  • 如果Hey 实例被垃圾回收,square.apply(23d) 将如何工作?
  • 唯一发生的事情是拒绝编译。您能否提供一个编译并可以提出相同问题的示例?

标签: java generics java-8 functional-interface


【解决方案1】:

范围是一个编译时概念,它控制源代码中名称的使用位置。 From the JLS

声明的范围是程序所在的区域 声明所声明的实体可以使用 简单的名称,只要它是可见的(§6.4.1)。

名称hey 仅限于标记为whatsGonnaHappen 的语句的主体这一事实与hey 在运行时引用的实例是否是垃圾收集的候选对象没有任何关系(我假设是你担心的)。

关于变量捕获,是的,方法引用hey::square 是对特定对象的实例方法的引用(由hey 引用的方法),因此将捕获变量hey 的值,当方法引用表达式被求值以产生一个实例并在调用apply 时使用它。

【讨论】:

    【解决方案2】:

    您的方法参考基本上等同于这样做:

    Hey hey = new Hey();
    Function<Double, Double> square = new DoubleDoubleFunction(hey);
    

    DoubleDoubleFunction 类是这样定义的

    class DoubleDoubleFunction implements Function<Double, Double> {
        private final Hey hey;
    
        public DoubleDoubleFunction(Hey hey) {
            this.hey = hey;
        }
    
        @Override
        public Double apply(Double num) {
            return hey.square(num);
        }
    }
    

    换句话说,square 持有对Hey 的引用。

    我不了解 eclipse,但使用 IntelliJ,您可以轻松地将方法引用和 lambda 转换为匿名/静态嵌套/内部类,以查看发生了什么。我觉得这是一件很有启发性的事情。

    【讨论】:

    • 您也可以这样做in Eclipse,感谢您的发现!
    猜你喜欢
    • 2019-07-25
    • 2020-07-12
    • 2020-08-10
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多