Nie można odwoływać się do niekończącej się zmiennej wewnątrz klasy wewnętrznej zdefiniowanej w innej metodzie

Edytowane: Muszę zmienić wartości kilku zmiennych, ponieważ uruchamiają się kilka razy. Muszę aktualizować wartości z każdą iteracją przez timer. Nie mogę ustawić wartości na ostateczne, ponieważ uniemożliwi mi to aktualizację wartości, jednak otrzymuję błąd, który opisuję w wstępnym pytaniu poniżej:

Napisałem wcześniej co jest poniżej:

Otrzymuję błąd " nie można odwoływać się do niekończącej się zmiennej wewnątrz klasy wewnętrznej zdefiniowana inną metodą".

Dzieje się to dla podwójnej ceny o nazwie price i ceny o nazwie priceObject. Wiesz, dlaczego mam ten problem? Nie rozumiem, dlaczego muszę mieć deklarację końcową. Również jeśli możecie zobaczyć, co próbuję zrobić, co muszę zrobić, aby obejść ten problem.

public static void main(String args[]) {

    int period = 2000;
    int delay = 2000;

    double lastPrice = 0;
    Price priceObject = new Price();
    double price = 0;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);
}
Author: Josh Lee, 2009-08-19

20 answers

Java nie obsługuje true closures , mimo że używanie anonimowej klasy, takiej jak tutaj (new TimerTask() { ... }), wygląda na zamknięcie.

Edytuj - Zobacz komentarze poniżej - poniższe Wyjaśnienie nie jest poprawne, jak podkreśla KeeperOfTheSoul.

Dlatego to nie działa:

Zmienne lastPrice i price są zmiennymi lokalnymi w metodzie main (). Obiekt utworzony za pomocą anonimowej klasy może trwać do po zwróceniu metody main().

Gdy Metoda main() zwróci, zmienne lokalne (takie jak lastPrice i price) zostaną oczyszczone ze stosu, więc nie będą już istnieć po zwróceniu main().

Ale obiekt klasy anonymous odwołuje się do tych zmiennych. Wszystko potoczyłoby się bardzo źle, gdyby anonimowy obiekt klasy próbował uzyskać dostęp do zmiennych po ich wyczyszczeniu.

Dokonując lastPrice i price final, nie są już tak naprawdę zmiennymi, ale stałymi. Kompilator może wtedy po prostu zastąpić użycie lastPrice i price w klasie anonimowej wartościami stałych (oczywiście w czasie kompilacji), i nie będzie już problemu z dostępem do nieistniejących zmiennych.

Inne języki programowania, które obsługują zamknięcia, robią to, traktując te zmienne specjalnie - upewniając się, że nie zostaną zniszczone po zakończeniu metody, tak aby zamknięcie mogło nadal uzyskać dostęp do zmiennych.

@ Ankur: mógłbyś to:
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
Author: Jesper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 17:13:58

Aby uniknąć dziwnych efektów ubocznych z zamknięciami w zmiennych java, do których odwołuje się anonimowy delegat, muszą być oznaczone jako ostateczne, więc aby odwołać się do lastPrice i ceny w zadaniu timera muszą być oznaczone jako ostateczne.

To oczywiście nie zadziała dla Ciebie, ponieważ chcesz je zmienić, w tym przypadku powinieneś spojrzeć na zamknięcie ich w klasie.

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

Teraz po prostu utwórz nowy Foo jako ostateczny i zadzwoń .tik z zegara.

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
Author: Chris Chilvers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-14 09:28:16

Możesz uzyskać dostęp do końcowych zmiennych z klasy zawierającej tylko wtedy, gdy używasz anonimowej klasy. Dlatego musisz zadeklarować, że używane zmienne są ostateczne (co nie jest opcją dla Ciebie, ponieważ zmieniasz lastpricei price), lub nie używaj anonimowej klasy.

Więc twoje opcje to stworzenie rzeczywistej klasy wewnętrznej, w której możesz przekazać zmienne i używać ich w normalny sposób

Lub:

Jest szybki (i moim zdaniem brzydki) hack dla Twojej lastPrice i price zmiennej, która ma ją zadeklarować tak

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

I w Twojej anonimowej klasie możesz ustawić wartość w ten sposób

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];
 18
Author: Robin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 13:24:27

Dobre wyjaśnienie, dlaczego nie możesz zrobić tego, co próbujesz zrobić już pod warunkiem. Jako rozwiązanie, może rozważyć:

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

Wydaje się, że prawdopodobnie mógłbyś zrobić lepszy projekt niż ten, ale chodzi o to, że możesz grupować zaktualizowane zmienne wewnątrz odniesienia do klasy, które się nie zmienia.

 13
Author: Peter Cardona,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 13:31:54

Z klasami anonimowymi, w rzeczywistości deklarujesz klasę zagnieżdżoną "bezimienną". W przypadku klas zagnieżdżonych kompilator generuje nową samodzielną klasę publiczną z konstruktorem, który weźmie wszystkie zmienne używane jako argumenty (dla klas zagnieżdżonych" nazwanych " jest to zawsze instancja oryginalnej/zamkniętej klasy). Dzieje się tak, ponieważ środowisko uruchomieniowe nie ma pojęcia o klasach zagnieżdżonych, więc musi być (automatyczna) konwersja z zagnieżdżonej klasy do samodzielnej klasy.

Take ten kod na przykład:

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

To nie zadziała, bo tak robi kompilator pod maską:

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

Oryginalna Klasa anonimowa jest zastępowana przez jakąś samodzielną klasę, którą kompilator generuje (kod nie jest dokładny, ale powinien dać ci dobry pomysł):

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

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

Jak widzisz, samodzielna klasa zawiera odniesienie do współdzielonego obiektu, pamiętaj, że wszystko w Javie jest wartością pass-by-value, więc nawet jeśli zmienna referencyjna 'shared' w EnclosingClass otrzyma zmienione, instancja, na którą wskazuje, nie jest modyfikowana, a wszystkie inne zmienne referencyjne wskazujące na nią (jak ta w klasie anonymous: Enclosing$1), nie będą tego świadome. Jest to główny powód, dla którego kompilator zmusza cię do zadeklarowania tych 'współdzielonych' zmiennych jako ostatecznych, tak aby tego typu zachowanie nie znalazło się w Twoim już działającym kodzie.

Oto, co się dzieje, gdy używasz zmiennej instancji wewnątrz anonimowej klasy (to jest to, co powinieneś zrobić, aby rozwiązać swój problem, przeniesienie logiki do metody "instance" lub konstruktora klasy):

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

To dobrze kompiluje, ponieważ kompilator zmodyfikuje kod, tak że nowa wygenerowana Klasa zamykająca$1 będzie zawierała odniesienie do instancji Encosingclass, w której została utworzona (jest to tylko reprezentacja, ale powinna cię zachęcić do działania):

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

W ten sposób, gdy zmienna referencyjna 'shared' W EnclosingClass zostanie ponownie przypisana, a stanie się to przed wywołaniem wątku # run (), zobaczysz "other hello" Wydrukowano dwa razy, ponieważ teraz enclosingclass$1#zmienna enclosingclass zachowa odniesienie do obiektu klasy, w której została zadeklarowana, więc zmiany dowolnego atrybutu na tym obiekcie będą widoczne dla instancji enclosingclass$1.

Aby uzyskać więcej informacji na ten temat, możesz zobaczyć ten doskonały wpis na blogu (Nie napisany przeze mnie): http://kevinboone.net/java_inner.html

 10
Author: emerino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-14 20:07:05

Kiedy natknąłem się na ten problem, po prostu przekazuję obiekty do klasy wewnętrznej przez konstruktor. Jeśli muszę przekazać podstawowe lub niezmienne obiekty (jak w tym przypadku), potrzebna jest klasa wrapper.

Edit: właściwie, w ogóle nie używam anonimowej klasy, ale odpowiedniej podklasy:

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
Author: Buhb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 13:55:00

Nie można odwoływać się do zmiennych niekończących się, ponieważ specyfikacja języka Java Tak mówi. Od 8.1.3:
"Każda zmienna lokalna, parametr metody formalnej lub parametr obsługi wyjątków użyta, ale nie zadeklarowana w klasie wewnętrznej musi być zadeklarowana jako ostateczna."cały akapit.
Widzę tylko część Twojego kodu - według mnie modyfikowanie harmonogramu zmiennych lokalnych jest dziwnym pomysłem. Zmienne lokalne przestają istnieć po opuszczeniu funkcji. Może statyczne pola klasy byłyby lepiej?

 2
Author: Tadeusz Kopec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 13:30:37

Napisałem coś do Uchwyt coś wzdłuż intencji autorów . Najlepszą rzeczą do zrobienia było pozwolić konstruktorowi wziąć wszystkie obiekty, a następnie w zaimplementowanej metodzie użyć tych obiektów konstruktora.

Jednakże, jeśli piszesz generyczną klasę interfejsu, musisz przekazać obiekt, lub lepiej listę obiektów. Można to zrobić za pomocą Object [] lub nawet lepiej, Object ...Ponieważ łatwiej jest zadzwonić.

Zobacz mój przykładowy kawałek poniżej.

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

}

Proszę zobaczyć ten post o Java closures, który obsługuje to po wyjęciu z pudełka: http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html

Wersja 1 wspiera przechodzenie niekończących się zamknięć z autocasting:
https://github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/blob/master/org/mo/closure/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
Author: momo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-09 17:47:14

Jeśli chcesz zmienić wartość w wywołaniu metody w anonimowej klasie, ta "wartość" jest w rzeczywistości Future. Tak więc, jeśli używasz Guava, możesz napisać

...
final SettableFuture<Integer> myvalue = SettableFuture<Integer>.create();
...
someclass.run(new Runnable(){

    public void run(){
        ...
        myvalue.set(value);
        ...
    }
 }

 return myvalue.get();
 2
Author: Earth Engine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 02:54:27

Jedno z rozwiązań, które zauważyłem, nie jest wymienione (chyba, że go przegapiłem, jeśli mnie poprawiłem), jest użycie zmiennej klasy. Napotkał ten problem podczas próby uruchomienia nowego wątku w metodzie: new Thread(){ Do Something }.

Wywołanie doSomething() z poniższego polecenia zadziała. Nie musisz koniecznie deklarować final, wystarczy zmienić zakres zmiennej, aby nie była pobierana przed innerclass. To chyba, że oczywiście twój proces jest ogromny i zmiana zakresu może stworzyć jakiś rodzaj konfliktu. Nie chciałem, aby moja zmienna była ostateczna, ponieważ w żaden sposób nie była ostateczna / stała.

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
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-16 15:22:01

Jeśli zmienna musi być ostateczna, nie może być wtedy możesz przypisać wartość zmiennej do innej zmiennej i uczynić ją ostateczną, więc możesz jej użyć zamiast tego.

 1
Author: Thorbjørn Ravn Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 13:39:12

Użyj Nazwy Klasy.to.variableName to reference the non-final variable

 1
Author: user3251651,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-17 23:48:33

Możesz po prostu zadeklarować zmienną poza zewnętrzną klasą. Następnie będziesz mógł edytować zmienną z poziomu klasy wewnętrznej. Czasami napotykam podobne problemy podczas kodowania w Androidzie, więc deklaruję zmienną jako globalną i działa dla mnie.

 1
Author: Abhijay Ghildyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-18 18:02:38

Czy potrafisz lastPrice, priceObject, i price pola anonimowej klasy wewnętrznej?

 0
Author: Greg Mattes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-24 20:47:21

Głównym problemem jest to, czy zmienna wewnątrz anonimowej instancji klasy może zostać rozwiązana w czasie wykonywania. Nie jest konieczne, aby zmienna była ostateczna, o ile jest zagwarantowane, że zmienna znajduje się w zakresie czasu wykonania. Na przykład patrz dwie zmienne _statusMessage i _statustextview wewnątrz metody 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
Author: WaiKit Kung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-23 12:43:16

Dla mnie zadziałało tylko zdefiniowanie zmiennej poza tą funkcją twojego.

Tuż przed deklaracją funkcji głównej tzn.

Double price;
public static void main(String []args(){
--------
--------
}
 0
Author: punkck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-26 01:18:51

Zadeklaruj zmienną jako statyczną i odwołaj się do niej w wymaganej metodzie używając className.zmienna

 0
Author: shweta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-23 05:20:27

Jeszcze jedno wyjaśnienie. Rozważ ten przykład poniżej
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");
    }
}

Tutaj wyjście będzie

M1]}

Thread t running

Thread t running

Thread t running

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

Teraz metoda m1() kończy się i przypisujemy zmienną odniesienia o do null , teraz zewnętrzny obiekt klasy kwalifikuje się do GC, ale wewnętrzny obiekt klasy nadal istnieje, który ma (ma-A) relację z uruchomionym obiektem wątku. Bez istniejącego obiektu klasy zewnętrznej nie ma szans na istnienie istniejącej metody m1() i bez istniejącej metody m1() nie ma szans na istnienie jej zmiennej lokalnej, ale jeśli obiekt klasy wewnętrznej używa zmiennej lokalnej metody m1 (), to wszystko jest oczywiste.

Aby to rozwiązać musimy utworzyć kopię lokalnej zmiennej i następnie skopiować ją do sterty z wewnętrznym obiektem klasy, co robi java tylko dla zmiennej końcowej, ponieważ nie są one w rzeczywistości zmienną są jak stałe (wszystko dzieje się w czasie kompilacji tylko nie w czasie wykonywania).

 0
Author: xTroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-05 08:07:52

Aby rozwiązać powyższy problem, różne języki podejmują różne decyzje.

W przypadku Javy rozwiązanie jest takie, jakie widzimy w tym artykule.

Dla C# rozwiązaniem jest allow side-effects i capture by reference jest jedyną opcją.

Dla C++11 rozwiązaniem jest umożliwienie programiście podjęcia decyzji. Mogą wybrać przechwytywanie według wartości lub odniesienia. Jeśli przechwytywanie według wartości, nie wystąpią żadne efekty uboczne, ponieważ zmienna, do której odwołuje się, jest w rzeczywistości Inna. Jeśli przechwytywanie przez odniesienie, mogą wystąpić efekty uboczne, ale programista powinien to zrealizować.

 -1
Author: Earth Engine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-19 02:08:47

Ponieważ jest to mylące, jeśli zmienna nie jest ostateczna, ponieważ zmiany w niej nie zostaną odebrane w klasie anonimowej.

Wystarczy, że zmienne "price" I "lastPrice" będą ostateczne.

-- Edit

UPS, a Ty też będziesz musiał nie przypisywać do nich, oczywiście, w swojej funkcji. Będziesz potrzebował nowych zmiennych lokalnych. Podejrzewam, że ktoś dał ci lepszą odpowiedź.

 -2
Author: Noon Silk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 13:31:13