переменная местоположения, доступная из внутреннего класса, должна быть объявлена ​​окончательной [дубликат]

Я бы сказал, что это pass-by-copy -

. Рассмотрение аргументов и объектов переменных - это объекты, созданные во время контекста выполнения, созданного в начале вызова функции, - и ваше фактическое значение / ссылка, переданная в функция просто хранится в этих аргументах + объекты переменных.

Проще говоря, для примитивных типов значения копируются в начале вызова функции, для типа объекта ссылка копируется.

235
задан Josh Lee 5 October 2010 в 20:01
поделиться

20 ответов

Java не поддерживает true closures , хотя использование анонимного класса, как вы используете здесь (new TimerTask() { ... }), похоже на закрытие.

edit - См. комментарии ниже - следующее объяснение не является правильным, как указывает KeeperOfTheSoul.

Вот почему он не работает:

Переменные lastPrice, а цена - это локальные переменные в методе main (). Объект, созданный с анонимным классом, может продолжаться до тех пор, пока метод main() не вернется.

Когда метод main() возвращается, локальные переменные (такие как lastPrice и price) будут очищены от стека, поэтому они больше не будут существовать после возвращения main().

Но объект анонимного класса ссылается на эти переменные. Все будет ужасно ошибочно, если объект анонимного класса попытается получить доступ к переменным после их очистки.

Сделав lastPrice и price final, они больше не являются переменными, но константы. Затем компилятор может просто заменить использование lastPrice и price в анонимном классе со значениями констант (во время компиляции, конечно), и у вас не будет проблемы с доступом к несуществующим переменным больше .

Другие языки программирования, которые поддерживают замыкания, делают это, рассматривая эти переменные специально - следя за тем, чтобы они не уничтожались, когда метод заканчивается, так что закрытие по-прежнему может получить доступ к переменным.

@Ankur: вы могли бы сделать это:

public static void main(String args[]) {
    int period = 2000;
    int delay = 2000;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        // Variables as member variables instead of local variables in main()
        private double lastPrice = 0;
        private Price priceObject = new Price();
        private double price = 0;

        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);      
}
191
ответ дан phoenix 22 August 2018 в 18:15
поделиться
  • 1
    Не совсем верно, Java действительно создает привязки для переменных, о которых идет речь, чтобы фиксировать их значения времени выполнения, просто они хотели избежать странного побочного эффекта, который возможен в .Net, когда вы фиксируете значение в делетете, измените значение во внешнем методе, и теперь делегат видит новое значение, см. stackoverflow.com/questions/271440/c-captured-variable-in-loop для примера C # такого поведения, которое предназначено для Java избегать. – Chris Chilvers 19 August 2009 в 14:29
  • 2
    Это не «странный побочный эффект», это нормальное поведение, которое люди ожидали бы - и какая Java не может доставить , потому что он не генерирует захваты. В качестве обходного пути локальные переменные, используемые в анонимном классе, должны быть окончательными. – Michael Borgwardt 19 August 2009 в 14:42
  • 3
    Джеспер, вы должны, вероятно, отредактировать неправильные части своих ответов, а не просто сообщение с сообщением о том, что это неверно. – James McMahon 5 October 2010 в 14:30
  • 4
    На самом деле Java не поддерживает закрытие. Языки, поддерживающие блокировки, делают это, сохраняя всю локальную среду (то есть набор локальных переменных, определенных в текущем фрейме стека) как объект кучи. У Java нет поддержки для этого (разработчики языка хотели реализовать его, но не хватало времени), так как обходной путь, когда создается локальный класс, значения любых локальных переменных, на которые он ссылается, копируются в кучу , Однако JVM не может сохранять значения в синхронизации с локальными переменными, поэтому они должны быть окончательными. – Taymon 4 March 2012 в 04:37
  • 5
    Этот ответ сейчас полностью запутан, потому что никто не назван «KeeperOfTheSoul». который прокомментировал это. Ответ должен быть пересмотрен. – Adam Parkin 6 March 2014 в 23:52

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

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

public class Foo {
    private PriceObject priceObject;
    private double lastPrice;
    private double price;

    public Foo(PriceObject priceObject) {
        this.priceObject = priceObject;
    }

    public void tick() {
        price = priceObject.getNextPrice(lastPrice);
        lastPrice = price;
    }
}

теперь просто создать новый Foo как final и вызовите .tick из таймера.

public static void main(String args[]){
    int period = 2000;
    int delay = 2000;

    Price priceObject = new Price();
    final Foo foo = new Foo(priceObject);

    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            foo.tick();
        }
    }, delay, period);
}
30
ответ дан Andrii Abramov 22 August 2018 в 18:15
поделиться
  • 1
    или вы можете просто привести Foo реализовать Runnable ..? – vidstige 13 December 2014 в 07:26

вы можете просто объявить переменную вне внешнего класса. После этого вы сможете редактировать переменную из внутреннего класса. Иногда я сталкиваюсь с аналогичными проблемами при кодировании в android, поэтому объявляю переменную глобальной, и она работает для меня.

1
ответ дан Aryan 22 August 2018 в 18:15
поделиться
  • 1
    Это на самом деле не отвечает на вопрос ... Его почему вы получаете downvoted. – Stuart Siegler 2 September 2015 в 10:26

Когда я спотыкаюсь на эту проблему, я просто передаю объекты во внутренний класс через конструктор. Если мне нужно передать примитивы или неизменяемые объекты (как в этом случае), необходим класс-оболочка.

Изменить: На самом деле я вообще не использую анонимный класс, но соответствующий подкласс:

public class PriceData {
        private double lastPrice = 0;
        private double price = 0;

        public void setlastPrice(double lastPrice) {
            this.lastPrice = lastPrice;
        }

        public double getLastPrice() {
            return lastPrice;
        }

        public void setPrice(double price) {
            this.price = price;
        }

        public double getPrice() {
            return price;
        }
    }

    public class PriceTimerTask extends TimerTask {
        private PriceData priceData;
        private Price priceObject;

        public PriceTimerTask(PriceData priceData, Price priceObject) {
            this.priceData = priceData;
            this.priceObject = priceObject;
        }

        public void run() {
            priceData.setPrice(priceObject.getNextPrice(lastPrice));
            System.out.println();
            priceData.setLastPrice(priceData.getPrice());

        }
    }

    public static void main(String args[]) {

        int period = 2000;
        int delay = 2000;

        PriceData priceData = new PriceData();
        Price priceObject = new Price();

        Timer timer = new Timer();

        timer.scheduleAtFixedRate(new PriceTimerTask(priceData, priceObject), delay, period);
    }
7
ответ дан Buhb 22 August 2018 в 18:15
поделиться

Чтобы решить проблему выше, разные языки принимают разные решения.

для Java, решение является тем, что мы видим в этой статье.

для C #, решение разрешает побочные эффекты и захват по ссылке - единственный вариант.

для C ++ 11, решение должно позволить программисту принять решение. Они могут выбрать захват по значению или по ссылке. Если захват по значению, никаких побочных эффектов не произойдет, потому что ссылка на переменную действительно отличается. Если захват по ссылке, могут возникнуть побочные эффекты, но программист должен это осознать.

2
ответ дан Earth Engine 22 August 2018 в 18:15
поделиться

С анонимными классами вы фактически объявляете «безымянный» вложенный класс. Для вложенных классов компилятор создает новый автономный публичный класс с конструктором, который будет принимать все переменные, которые он использует в качестве аргументов (для «названных» вложенных классов это всегда является экземпляром исходного / охватывающего класса). Это делается потому, что среда выполнения не имеет понятия вложенных классов, поэтому должно быть (автоматическое) преобразование из вложенного в автономный класс.

Возьмите этот код, например:

public class EnclosingClass {
    public void someMethod() {
        String shared = "hello"; 
        new Thread() {
            public void run() {
                // this is not valid, won't compile
                System.out.println(shared); // this instance expects shared to point to the reference where the String object "hello" lives in heap
            }
        }.start();

        // change the reference 'shared' points to, with a new value
        shared = "other hello"; 
        System.out.println(shared);
    }
}

Это не сработает, потому что это то, что делает компилятор под капотом:

public void someMethod() {
    String shared = "hello"; 
    new EnclosingClass$1(shared).start();

    // change the reference 'shared' points to, with a new value
    shared = "other hello"; 
    System.out.println(shared);
}

Исходный анонимный класс заменяется некоторым автономным классом, который генерирует компилятор (код не является точным, но должен дать вам хорошую идею):

public class EnclosingClass$1 extends Thread {
    String shared;
    public EnclosingClass$1(String shared) {
        this.shared = shared;
    }

    public void run() {
        System.out.println(shared);
    }
}

Как вы можете видеть, автономный класс содержит ссылку к общему объекту, помните, что все в java имеет значение pass-by-value, поэтому, даже если ссылочная переменная «shared» в EnclosingClass изменяется, экземпляр, на который он указывает, не изменяется, и все остальные ссылочные переменные, указывающие на него (например, один в анонимном классе: Enclosing $ 1), не будет знать об этом. Это основная причина, по которой компилятор заставляет вас объявлять эти «общие» переменные окончательными, чтобы этот тип поведения не попадал в ваш уже запущенный код.

Теперь это происходит, когда вы используете переменную экземпляра внутри анонимного класса (это то, что вы должны сделать, чтобы решить вашу проблему, переместить логику в метод «экземпляр» или конструктор класса ):

public class EnclosingClass {
    String shared = "hello";
    public void someMethod() {
        new Thread() {
            public void run() {
                System.out.println(shared); // this is perfectly valid
            }
        }.start();

        // change the reference 'shared' points to, with a new value
        shared = "other hello"; 
        System.out.println(shared);
    }
}

Это компилируется отлично, потому что компилятор изменит код, так что новый сгенерированный класс Enclosing $ 1 будет содержать ссылку на экземпляр EnclosingClass, где он был создан (это только представление, но вам нужно идти):

public void someMethod() {
    new EnclosingClass$1(this).start();

    // change the reference 'shared' points to, with a new value
    shared = "other hello"; 
    System.out.println(shared);
}

public class EnclosingClass$1 extends Thread {
    EnclosingClass enclosing;
    public EnclosingClass$1(EnclosingClass enclosing) {
        this.enclosing = enclosing;
    }

    public void run() {
        System.out.println(enclosing.shared);
    }
}

Подобно этому, когда ссылочная переменная 'shared' в EnclosingClass переназначается, и это происходит до вызова Thread # run (), вы будете см. «другое привет», напечатанное дважды, потому что теперь EnclosingClass $ 1 # вмещающая переменная будет содержать ссылку на объект класса, где она была объявлена, поэтому изменения любого атрибута на этом объекте будут видны экземплярам EnclosingClass $ 1.

Для получения дополнительной информации по этому вопросу вы можете увидеть это замечательное сообщение в блоге (не написано мной): http: // kevinbo one.net/java_inner.html

10
ответ дан emerino 22 August 2018 в 18:15
поделиться
  • 1
    Позаботьтесь о том, почему голосуете? Я не вижу ничего плохого в приведенном выше объяснении. – emerino 18 December 2014 в 19:56
  • 2
    Что делать, если локальная переменная «shared» является изменчивым объектом? В соответствии с вашим объяснением объявление «окончательного» тоже не поможет, верно? – sactiw 19 April 2017 в 13:11
  • 3
    Объявление & quot; общий & quot; поскольку final позволит вам изменить состояние объекта, ссылки на конечную переменную, но для этого конкретного примера, который не будет работать, потому что вы не сможете изменить значение «shared», переменная (что и требовался OP), вы сможете использовать ее внутри анонимных классов, но ее значение не изменится (поскольку оно объявлено окончательным). Важно заметить разницу между переменными и фактическими значениями, которые они содержат (которые могут быть примитивами или ссылками на объекты в куче). – emerino 19 April 2017 в 23:44
  • 4
    <Я> & GT; & GT; & GT; но это значение не изменится. Я думаю, вам не хватает точки, т. е. если конечная ссылочная переменная указывает на изменяемый объект, он все равно может быть обновлен, однако анонимный класс создает мелкую копию, поэтому изменения отражаются в анонимный класс. Другими словами, состояние синхронизировано, что является желательным здесь. Здесь OP нуждается в возможности изменить общую переменную (примитивный тип), и для достижения этого OP необходимо будет обернуть значение под изменяемым объектом и передать этот изменяемый объект. – sactiw 20 April 2017 в 06:53
  • 5
    Конечно, OP может обернуть необходимое значение под изменяемым объектом, объявить переменную как final и использовать ее вместо этого. Однако он может избежать использования дополнительного объекта, объявив переменную как атрибут текущего класса (как указано и объяснено в ответе). Невозможно использовать принудительные переменные объекты (например, использовать массивы, чтобы иметь возможность изменять значение общей переменной). – emerino 21 April 2017 в 08:43

Можете ли вы сделать поля lastPrice, priceObject и price анонимного внутреннего класса?

0
ответ дан Greg Mattes 22 August 2018 в 18:15
поделиться

Я только что написал что-то, чтобы что-то описать по намерениям авторов. Я нашел, что лучше всего было бы позволить конструктору взять все объекты, а затем в реализованном методе использовать объекты-конструкторы.

Однако, если вы пишете общий класс интерфейса, вам необходимо передать объект или лучше список объектов. Это может быть сделано Object [] или даже лучше, Object ... потому что его легче вызвать.

См. Мою часть примера чуть ниже.

List<String> lst = new ArrayList<String>();
lst.add("1");
lst.add("2");        

SomeAbstractClass p = new SomeAbstractClass (lst, "another parameter", 20, true) {            

    public void perform( ) {                           
        ArrayList<String> lst = (ArrayList<String>)getArgs()[0];                        
    }

};

public abstract class SomeAbstractClass{    
    private Object[] args;

    public SomeAbstractClass(Object ... args) {
        this.args = args;           
    }      

    public abstract void perform();        

    public Object[] getArgs() {
        return args;
    }

}

Пожалуйста, смотрите это сообщение о закрытии Java, которое поддерживает это из коробки: http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html

Версия 1 поддерживает передачу нефинальных замыканий с автозапуском: https://github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/blob/master/ org / mo / close / v1 / Closure.java

    SortedSet<String> sortedNames = new TreeSet<String>();
    // NOTE! Instead of enforcing final, we pass it through the constructor
    eachLine(randomFile0, new V1<String>(sortedNames) {
        public void call(String line) {
            SortedSet<String> sortedNames = castFirst();  // Read contructor arg zero, and auto cast it
            sortedNames.add(extractName(line));
        }
    });
2
ответ дан momo 22 August 2018 в 18:15
поделиться

Потому что это запутывает, если переменная не является окончательной, так как изменения в ней не будут отобраны в анонимном классе.

Просто сделайте окончательные значения переменных «price» и «lastPrice».

- Изменить

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

-2
ответ дан Noon Silk 22 August 2018 в 18:15
поделиться
  • 1
    его не просто путают - его совершенно неправильно, поэтому компилятор этого не допускает. – Chii 19 August 2009 в 14:19
  • 2
    Но как мне изменить значения, когда мне нужно? – Ankur 19 August 2009 в 14:20
  • 3
    Не только потому, что это сбивает с толку; это связано с тем, что Java не поддерживает закрытие. См. Мой ответ ниже. @Ankur: вы можете сделать переменные-члены-переменные объекта анонимного класса вместо локальных переменных в main (). – Jesper 19 August 2009 в 14:25
  • 4
    Он их модифицирует, поэтому они не могут быть окончательными. – Robin 19 August 2009 в 14:26
  • 5
    Если цена и lastPrice были окончательными, присваивания им не собирались. – Greg Mattes 19 August 2009 в 14:26

Хорошие объяснения, почему вы не можете делать то, что вы пытаетесь сделать уже предоставленным. В качестве решения можно подумать:

public class foo
{
    static class priceInfo
    {
        public double lastPrice = 0;
        public double price = 0;
        public Price priceObject = new Price ();
    }

    public static void main ( String args[] )
    {

        int period = 2000;
        int delay = 2000;

        final priceInfo pi = new priceInfo ();
        Timer timer = new Timer ();

        timer.scheduleAtFixedRate ( new TimerTask ()
        {
            public void run ()
            {
                pi.price = pi.priceObject.getNextPrice ( pi.lastPrice );
                System.out.println ();
                pi.lastPrice = pi.price;

            }
        }, delay, period );
    }
}

Похоже, что вы могли бы сделать лучший дизайн, чем это, но идея состоит в том, что вы можете группировать обновленные переменные внутри ссылки класса, которая не изменяется.

13
ответ дан Peter Cardona 22 August 2018 в 18:15
поделиться

то, что сработало для меня, просто определяет переменную вне этой функции вашего.

Перед тем, как основная функция объявит i.e.

Double price;
public static void main(String []args(){
--------
--------
}
0
ответ дан punkck 22 August 2018 в 18:15
поделиться
  • 1
    Это не сработает, вы объявляете переменную экземпляра, чтобы использовать ее, вам нужно создать экземпляр внутри вашего основного метода. Вы должны быть более конкретными или просто добавлять статический модификатор к переменной «цена». – emerino 23 December 2014 в 22:47

При использовании анонимного класса вы можете получить доступ только к конечным переменным из содержащего класса. Поэтому вам нужно объявить, что переменные используются final (что не является для вас вариантом, поскольку вы меняете lastPrice и price ) или не используете анонимный класс.

Итак, ваши возможности - создать реальный внутренний класс, в котором вы можете перейти в переменные и использовать их обычным способом

или:

Там (и, на мой взгляд, уродливый) взломать вашу переменную lastPrice и price , которая должна объявить ее так

final double lastPrice[1];
final double price[1];

и в ваш анонимный класс вы можете установить значение, подобное этому

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];
18
ответ дан Robin 22 August 2018 в 18:15
поделиться
  • 1
    Превосходный ответ. Это то, что я люблю, играя в систему;) много благодарностей! +1 для гения !!! – Roshana Pitigala 28 June 2018 в 17:45

Объявить переменную как статическую и ссылаться на нее в требуемом методе с помощью className.variable

0
ответ дан shweta 22 August 2018 в 18:15
поделиться
  • 1
    Non-static parameter cannot be referenced from a static context – surfer190 16 March 2015 в 15:59
  • 2
    @Shweta локальные переменные и параметры метода не могут быть объявлены «статическими», более того, речь идет о том, как он был реализован, чтобы позволить классам внутри методов (локальные анонимные классы) продолжать доступ к локальным переменным и параметрам метода даже после метода вернулся, т.е. он делает свои «окончательные» копии и использует их как переменные экземпляра. – sactiw 18 June 2015 в 11:08

Одно из решений, о которых я заметил, не упоминается (если я не пропустил его, если бы я исправил меня), это использование переменной класса. В этой проблеме возникла попытка запустить новый поток внутри метода: new Thread(){ Do Something }.

Вызов doSomething() из следующего будет работать. Вам необязательно объявлять его final, просто нужно изменить область действия переменной, чтобы она не была собрана перед внутренним классом. Это, если, конечно, ваш процесс не огромен, и изменение сферы может создать какой-то конфликт. Я не хотел, чтобы моя переменная была окончательной, поскольку она не была окончательной / константой.

public class Test
{

    protected String var1;
    protected String var2;

    public void doSomething()
    {
        new Thread()
        {
            public void run()
            {
                System.out.println("In Thread variable 1: " + var1);
                System.out.println("In Thread variable 2: " + var2);
            }
        }.start();
    }

}
2
ответ дан surfer190 22 August 2018 в 18:15
поделиться

Вы не можете ссылаться на не конечные переменные, потому что Java Language Specification так говорит. Из раздела 8.1.3: «Любая локальная переменная, параметр формального метода или параметр обработчика исключений, используемые, но не объявленные во внутреннем классе, должны быть объявлены окончательными». Полный абзац. Я вижу только часть вашего кода - по моему мнению, изменение локальных переменных - это странная идея. Локальные переменные перестают существовать, когда вы покидаете функцию. Может быть, статические поля класса будут лучше?

2
ответ дан Tadeusz Kopec 22 August 2018 в 18:15
поделиться

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

1
ответ дан Thorbjørn Ravn Andersen 22 August 2018 в 18:15
поделиться

использовать ClassName.this.variableName для ссылки на не конечную переменную

1
ответ дан user3251651 22 August 2018 в 18:15
поделиться

Основная проблема заключается в том, можно ли разрешить переменную внутри экземпляра анонимного класса во время выполнения. Не обязательно делать переменную final, если она гарантирована, что переменная находится внутри области выполнения. Например, просмотрите две переменные _statusMessage и _statusTextView внутри метода updateStatus ().

public class WorkerService extends Service {

Worker _worker;
ExecutorService _executorService;
ScheduledExecutorService _scheduledStopService;

TextView _statusTextView;


@Override
public void onCreate() {
    _worker = new Worker(this);
    _worker.monitorGpsInBackground();

    // To get a thread pool service containing merely one thread
    _executorService = Executors.newSingleThreadExecutor();

    // schedule something to run in the future
    _scheduledStopService = Executors.newSingleThreadScheduledExecutor();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    ServiceRunnable runnable = new ServiceRunnable(this, startId);
    _executorService.execute(runnable);

    // the return value tells what the OS should
    // do if this service is killed for resource reasons
    // 1. START_STICKY: the OS restarts the service when resources become
    // available by passing a null intent to onStartCommand
    // 2. START_REDELIVER_INTENT: the OS restarts the service when resources
    // become available by passing the last intent that was passed to the
    // service before it was killed to onStartCommand
    // 3. START_NOT_STICKY: just wait for next call to startService, no
    // auto-restart
    return Service.START_NOT_STICKY;
}

@Override
public void onDestroy() {
    _worker.stopGpsMonitoring();
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

class ServiceRunnable implements Runnable {

    WorkerService _theService;
    int _startId;
    String _statusMessage;

    public ServiceRunnable(WorkerService theService, int startId) {
        _theService = theService;
        _startId = startId;
    }

    @Override
    public void run() {

        _statusTextView = MyActivity.getActivityStatusView();

        // get most recently available location as a latitude /
        // longtitude
        Location location = _worker.getLocation();
        updateStatus("Starting");

        // convert lat/lng to a human-readable address
        String address = _worker.reverseGeocode(location);
        updateStatus("Reverse geocoding");

        // Write the location and address out to a file
        _worker.save(location, address, "ResponsiveUx.out");
        updateStatus("Done");

        DelayedStopRequest stopRequest = new DelayedStopRequest(_theService, _startId);

        // schedule a stopRequest after 10 seconds
        _theService._scheduledStopService.schedule(stopRequest, 10, TimeUnit.SECONDS);
    }

    void updateStatus(String message) {
        _statusMessage = message;

        if (_statusTextView != null) {
            _statusTextView.post(new Runnable() {

                @Override
                public void run() {
                    _statusTextView.setText(_statusMessage);

                }

            });
        }
    }

}
0
ответ дан WaiKit Kung 22 August 2018 в 18:15
поделиться

Просто другое объяснение. Рассмотрим этот пример ниже

public class Outer{
     public static void main(String[] args){
         Outer o = new Outer();
         o.m1();        
         o=null;
     }
     public void m1(){
         //int x = 10;
         class Inner{
             Thread t = new Thread(new Runnable(){
                 public void run(){
                     for(int i=0;i<10;i++){
                         try{
                             Thread.sleep(2000);                            
                         }catch(InterruptedException e){
                             //handle InterruptedException e
                         }
                         System.out.println("Thread t running");                             
                     }
                 }
             });
         }
         new Inner().t.start();
         System.out.println("m1 Completes");
    }
}

Здесь Выход будет

m1 Завершено

Резьба t работает

Работа потока t

]

Thread t running

................

Теперь метод m1 () завершается, и мы присваиваем ссылочную переменную o null, теперь объект Outer Class имеет право на GC, но объект Inner Class Object все еще существует, у которого есть (Has-A) связь с потоковым объектом, который запущен. Без существующего объекта Outer class нет возможности для существующего метода m1 (), и без существующего метода m1 () нет возможности создать свою локальную переменную, но если Inner Class Object использует локальную переменную метода m1 (), тогда все будет понятно .

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

0
ответ дан xTroy 22 August 2018 в 18:15
поделиться

Если вы хотите изменить значение в вызове метода в анонимном классе, это «значение» на самом деле является URL. Итак, если вы используете Guava, вы можете написать

HTML5
2
ответ дан Earth Engine 5 November 2018 в 15:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: