什么是关闭?java有封闭吗?

sus*_*ani 23 javascript java closures

我正在阅读面向对象的Javascript,并发现了闭包的概念.我不太明白为什么以及何时使用它.像Java这样的其他语言也有闭包吗?我基本上想了解如何了解闭包的概念可以帮助我改进编码.

mik*_*era 24

闭包是具有绑定变量的第一类函数.

大致意味着:

  • 您可以将闭包作为参数传递给其他函数
  • 闭包存储了一些变量的值,这些变量来自创建时存在的词法范围

Java最初没有对闭包的语法支持(这些是在Java 8中引入的),尽管使用匿名内部类来模拟它们是相当普遍的做法.这是一个例子:

import java.util.Arrays;
import java.util.Comparator;

public class StupidComparator { 
    public static void main(String[] args) {
        // this is a value used (bound) by the inner class
        // note that it needs to be "final"
        final int numberToCompareTo=10;

        // this is an inner class that acts like a closure and uses one bound value
        Comparator<Integer> comp=new Comparator<Integer>() {
            public int compare(Integer a, Integer b) {
                int result=0;
                if (a<numberToCompareTo) result=result-1;
                if (b<numberToCompareTo) result=result+1;
                return result;
            }
        };

        Integer[] array=new Integer[] {1,10, 5 , 15, 6 , 20, 21, 3, 7};

        // this is a function call that takes the inner class "closure" as a parameter
        Arrays.sort(array,comp);

        for (int i:array) System.out.println(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 第一类函数意味着您可以像对待该语言中的任何其他“对象”一样对待该函数,即将其作为参数传递,将其存储在集合中等。由于匿名内部类代表一个 Java 对象,就像任何其他对象一样对象,它是 Java 中的“一流”——你可以对它做任何你可以对任何其他普通对象做的事情 (3认同)
  • @DavidS我想说,区别在于语言语法自然支持的闭包与寻找另一种方法来实现相同效果(这在任何图灵完备的语言中最终都是可能的)。从 Java 8 开始,Java 实际上对闭包提供了相当不错的语法支持,作为 Lambda 表达式支持的一部分引入。 (2认同)

Oll*_*rds 13

关闭是以各种语言的各种名称知道的,但基本要点如下:

要创建闭包,您需要一种语言,其中函数类型是一等公民,即它可以绑定到变量并像任何旧字符串,int或bool一样传递.

您还需要能够内联声明函数.在javascript中你可以做这样的事情:

foo("bar", "baz" function(x){alert("x")});
Run Code Online (Sandbox Code Playgroud)

将匿名函数作为参数传递给foo函数.我们可以用它来创建一个闭包.

闭包"关闭"变量因此可用于传递范围变量.考虑这个例子:

function foo(){
    var spam = " and eggs";
    return function(food){alert(food + spam)};
}
var sideOfEggs = foo();
Run Code Online (Sandbox Code Playgroud)

鸡蛋的一面现在包含一个功能,它将"和鸡蛋"添加到它通过的任何食物中.垃圾邮件变量是foo函数范围的一部分,并且在函数退出时会丢失,除非闭包"关闭"命名空间,只要闭包保留在内存中,它就会保留它.

所以我们很清楚有权访问父母的私有范围变量吗?那么如何使用它们来模拟javascript中的私有访问修饰符呢?

var module = (function() {   
    var constant = "I can not be changed";

     return {
         getConstant    :    function() {  //This is the closure
            return constant;               //We're exposing an otherwise hidden variable here
         }
    };
}());                                     //note the function is being defined then called straight away

module.getConstant();                     //returns "I can not be changed"
module.constant = "I change you!";
module.getConstant();                     //still returns "I can not be changed" 
Run Code Online (Sandbox Code Playgroud)

所以这里发生的是我们正在创建并立即调用匿名函数.函数中有一个私有变量.它返回一个带有引用此变量的方法的对象.函数退出后,getConstant方法是访问变量的唯一方法.即使删除或替换此方法,也不会放弃它的秘密.我们使用闭包来实现封装和变量隐藏.有关详细说明,请参阅http://javascript.crockford.com/private.html

Java还没有闭包.它最接近的是匿名内部类.然而,为了实例化这些内联中的一个,你必须实例化一个完整的对象(通常来自现有的接口).封闭的美妙之处在于它们封装了简单,富有表现力的语句,这些语句在匿名内部类的噪音中有些丢失.


Sou*_*man 8

虽然Java没有一流的功能,但事实上它确实有词法闭包.

例如,以下Lisp函数(从Paul Graham的书"On Lisp"中窃取)返回一个添加数字的函数:

(defun make-adder (n)
  (lambda (x) (+ x n))
Run Code Online (Sandbox Code Playgroud)

这可以用Java完成.但是,由于它没有第一类函数,我们需要定义一个接口(让我们称之为Adder)和一个带有实现此接口的函数的匿名内部类.

public interface Adder {
    int add(int x);
}

public static Adder makeAdder(final int n) {
    return new Adder() {
        public int add(int x) {
            return x + n;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

内部的add()函数是一个词法闭包,因为它使用了外部词法范围中的n变量.

为了做到这一点,变量必须被声明为final,这意味着变量不能改变.但是,即使它们是最终的,也可以更改参考变量中的值.例如,考虑以下Lisp函数(也来自On Lisp):

(defun make-adderb (n)
  (lambda (x &optional change)
    (if change
        (setq n x)
        (+ n n))))
Run Code Online (Sandbox Code Playgroud)

这可以通过将外部变量包装在引用类型变量(例如数组或对象)中来实现.

public interface MutableAdder {
    int add(int x, boolean change);
}

public static MutableAdder makeAdderB(int n) {
    final int[] intHolder = new int[] { n };
    return new MutableAdder() {
        public int add(int x, boolean change) {
            if (change) {
                intHolder[0] = x;
                return x;
            }
            else {
                return intHolder[0] + x;
            }
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

我会声称这是真正的词汇封闭,而不是模拟.但我不会声称它很漂亮.