Подтвердить что ты не робот

Что такое закрытие? У java есть закрытие?

Я читал объектно-ориентированный Javascript и нашел концепцию замыканий. Я не совсем понял, почему и когда он используется. У других языков, таких как Java, также есть закрытие? Я в основном хочу понять, как знание концепции закрытия может помочь мне улучшить мою кодировку.

4b9b3361

Ответ 1

Замыкание является функцией первого класса со связанными переменными.

Примерно это означает, что:

  • Вы можете передать закрытие в качестве параметра другим функциям
  • Закрытие сохраняет значение некоторых переменных из лексической области, существовавшей в момент создания

У 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);
    }
}

Ответ 2

Замыкания известны различными именами на разных языках, но важными являются следующие моменты:

Для создания закрытий вам нужен язык, где тип функции является гражданином первого класса, то есть он может быть привязан к переменной и передан как любая старая строка, int или bool.

Вы также должны иметь возможность объявлять функции inline. В javascript вы можете сделать что-то вроде этого:

foo("bar", "baz" function(x){alert("x")});

Передача анонимной функции в качестве параметра функции foo. Мы можем использовать это для создания замыкания.

Замыкания "закрывают" переменные, поэтому их можно использовать для передачи облачных переменных. Рассмотрим этот пример:

function foo(){
    var spam = " and eggs";
    return function(food){alert(food + spam)};
}
var sideOfEggs = foo();

Сторона яиц теперь содержит функцию, которая добавляет "и яйца" к любому пищевому продукту, который он передает. Переменная спама является частью области функций 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" 

Итак, что происходит здесь, мы создаем и сразу вызываем анонимную функцию. В функции есть одна частная переменная. Он возвращает объект с единственным методом, который ссылается на эту переменную. Как только функция вышла, метод getConstant является единственным способом доступа к переменной. Даже если этот метод будет удален или заменен, он не откажется от него в секрете. Мы использовали закрытие для обеспечения инкапсуляции и сглаживания переменных. Для более подробного объяснения этого см. http://javascript.crockford.com/private.html

Java не имеет закрытий (пока). Самое близкое к нему - анонимные внутренние классы. Однако для создания экземпляра одного из них необходимо создать экземпляр целого объекта (обычно из существующего интерфейса). Красота закрытий - это инкапсуляция простых выразительных высказываний, которые несколько теряются в шуме анонимных внутренних классов.

Ответ 3

В то время как Java не имеет первоклассных функций, на самом деле они имеют лексические замыкания.

Например, следующая функция Lisp (украденная из книги Пола Грэма On Lisp) возвращает функцию, которая добавляет число:

(defun make-adder (n)
  (lambda (x) (+ x n))

Это можно сделать на 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;
        }
    };
}

Внутренняя функция add() является лексическим замыканием, потому что она использует переменную n из внешней лексической области.

Для этого переменная должна была быть объявлена ​​ final, что означает, что переменная не может измениться. Однако изменение значений в ссылочных переменных возможно, даже если они являются окончательными. Например, рассмотрим следующую функцию Lisp (также от On Lisp):

(defun make-adderb (n)
  (lambda (x &optional change)
    (if change
        (setq n x)
        (+ n n))))

Это может быть реализовано в Java путем обертывания внешней переменной в переменной ссылочного типа, например массивом или объектом.

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;
            }
        }
    };
}

Я буду утверждать, что это реальные лексические замыкания, а не симуляция. Но я не буду утверждать, что это довольно.

Ответ 4

Закрытие - это метод определения области охвата. Java не имеет закрытий.

В javascript вы можете сделать что-то вроде следующего:

var scope = this;

var f = function() {
    scope.somethingOnScope //scope is 'closed in' 
}

если вы затем сделаете что-то вроде pass f для функции, scope - это область определения, где она была определена.

Ответ 5

Закрытие - очень естественная функция, позволяющая захватывать свободные переменные своей лексической средой.

вот пример в javascript:

function x() {

    var y = "apple";

    return (function() {
         return y;
    });
}
Функция

возвращает функцию x. обратите внимание, что при создании функции переменные, используемые в этой функции, не оцениваются, как при возврате выражения. когда функция создается, она смотрит, какие переменные не являются локальными для функции (бесплатно). Затем он находит эти свободные переменные и гарантирует, что они не собираются в мусор, чтобы их можно было использовать, как только функция фактически вызывается.

Для поддержки этой функции вам необходимо иметь первоклассные функции, которые java не поддерживает.

Обратите внимание, что мы можем иметь частные переменные в таких языках, как JavaScript.