Farklı bir yöntemde tanımlanan bir iç sınıf içindeki nihai olmayan bir değişkene atıf yapılamaz


247

Düzenlendi: Bir zamanlayıcı thorugh birkaç kez çalıştıkça çeşitli değişkenlerin değerlerini değiştirmek gerekiyor. Zamanlayıcı üzerinden her yinelemeyle değerleri güncellemeye devam etmeliyim. Değerleri güncellememi engelleyecek gibi değerleri son olarak ayarlayamıyorum, ancak aşağıdaki ilk soruda açıkladığım hatayı alıyorum:

Daha önce aşağıda ne yazmıştım:

"Farklı bir yöntemde tanımlanan bir iç sınıf içinde son olmayan bir değişkene başvuramaz" hatası alıyorum.

Bu fiyat denilen çift fiyat ve priceObject denilen fiyat için oluyor. Bu sorunu neden aldığımı biliyor musunuz? Son bir bildirime neden ihtiyacım olduğunu anlamıyorum. Ayrıca ne yapmaya çalıştığımı görebiliyorsanız, bu sorunun üstesinden gelmek için ne yapmam gerekiyor.

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

Ne soruyorum, sürekli güncelleyebileceğim bir zamanlayıcıda bir değişkeni nasıl alabilirim.
Ankur

1
@Ankur: Basit cevap "Hayır". Ancak bir iç sınıf kullanarak istediğiniz efekti elde edebilirsiniz; @ petercardona'nın cevabına bakınız.
Stephen C

Yanıtlar:


197

Burada kullandığınız gibi anonim bir sınıf kullanmak ( ) bir tür kapatma gibi görünse de Java gerçek kapanmaları desteklemez new TimerTask() { ... }.

edit - Aşağıdaki yorumlara bakın - KeeperOfTheSoul'un işaret ettiği gibi, aşağıdakiler doğru bir açıklama değildir.

Bu yüzden çalışmıyor:

Değişkenler lastPriceve fiyat main () yöntemindeki yerel değişkenlerdir. Anonim sınıfla oluşturduğunuz nesne, main()yöntem geri dönene kadar sürebilir .

Tüm main()yöntem geri döndüğünde, (örneğin, yerel değişkenler lastPriceve price) istiften temizlenmiş olacak, bu yüzden bunlar daha sonra artık mevcut olmayacak main()getiri.

Ancak anonim sınıf nesnesi bu değişkenlere başvurur. Anonim sınıf nesnesi, değişkenler temizlendikten sonra erişmeye çalışırsa işler korkunç şekilde yanlış gider.

Yaparak lastPriceve price finalbunlar artık değişkenler, ancak sabitler gerçekten değildir. Derleyici sonra sadece kullanımını değiştirebilir lastPriceve price(tabii ki, derleme zamanında) sabitler değerleri ile anonim sınıfında ve artık varolmayan değişkenleri erişme ile sorun olmaz.

Kapakları destekleyen diğer programlama dilleri, bu değişkenleri özel olarak ele alarak yapar - yöntem sona erdiğinde yok edilmemelerini sağlayarak, kapağın değişkenlere hala erişebilmesi için.

@Ankur: Bunu yapabilirsin:

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

34
Tam olarak doğru değil, Java, söz konusu değişkenler için çalışma zamanı değerlerini yakalamak için yakalar oluşturur, sadece. Delege'deki değeri yakaladığınız, dış yöntemde değer ve şimdi temsilci yeni değer görmem görür stackoverflow.com/questions/271440/c-captured-variable-in-loop Java amaçları önlemek için bu davranış C # örneğin.
Chris Chilvers

14
Bir "garip yan etkisi" değil Yani, normal bir davranış insanların beklenebilir - ve hangi Java teslim edemez , çünkü o yakalar oluşturmaz. Geçici bir çözüm olarak, anonim bir sınıfta kullanılan yerel değişkenler son olmalıdır.
Michael Borgwardt

12
Jesper, muhtemelen yukarıdaki mesajların yanlış olduğunu söyleyen bir mesaj almak yerine cevaplarınızın yanlış kısımlarını düzenlemelisiniz.
James McMahon

19
Java aslında kapanışları desteklemez. Kapanışları destekleyen diller, tüm yerel ortamı (geçerli yığın çerçevesinde tanımlanan yerel değişkenler kümesini) bir yığın nesnesi olarak depolayarak bunu yapar. Java bunun için desteğe sahip değildir (dil tasarımcıları uygulamak istedi, ancak zaman tükendi), bu nedenle bir geçici çözüm olarak, yerel bir sınıf her başlatıldığında, başvurduğu herhangi bir yerel değişkenin değerleri yığın üzerine kopyalanır . Ancak, JVM değerleri yerel değişkenlerle senkronize tutamaz, bu yüzden nihai olmaları gerekir.
Taymon

64
Bu cevap, "KeeperOfTheSoul" adında yorum yapan kimse olmadığı için tamamen kafa karıştırıcı. Cevap gözden geçirilmelidir.
Adam Parkin

32

Anonim bir temsilci tarafından başvurulan java değişkenlerindeki kapanışlarla garip yan etkilerden kaçınmak için son olarak işaretlenmelidir, bu nedenle lastPricezamanlayıcı görevine başvurmak ve fiyat için nihai olarak işaretlenmeleri gerekir.

Bu sizin için işe yaramayacaktır, çünkü onları değiştirmek istiyorsunuz, bu durumda onları bir sınıfta kapsüllemeye bakmalısınız.

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

şimdi final olarak yeni bir Foo oluşturun ve zamanlayıcıdan .tick'i arayın.

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

1
ya da sadece Foo Runnable uygulamak yol açabilir ..?
vidstige

18

Anonim bir sınıf kullanırken yalnızca kapsayıcı sınıftaki son değişkenlere erişebilirsiniz. Bu nedenle, son kullanılan değişkenleri bildirmeniz gerekir ( lastPrice ve fiyatı değiştirdiğiniz için sizin için bir seçenek değildir ) veya anonim bir sınıf kullanmayın.

Yani seçenekleriniz, değişkenleri aktarabileceğiniz ve normal bir şekilde kullanabileceğiniz gerçek bir iç sınıf yaratmaktır.

veya:

LastPrice ve fiyat değişkeniniz için hızlı (ve bence çirkin) bir kesmek var

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

ve anonim sınıfınızda değeri şu şekilde ayarlayabilirsiniz

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];

14

Yapmaya çalıştığınız şeyi neden yapamadığınıza dair iyi açıklamalar zaten sağlandı. Bir çözüm olarak düşünün:

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

Muhtemelen bundan daha iyi bir tasarım yapabilirsiniz, ancak fikir, güncellenen değişkenleri değişmeyen bir sınıf başvurusu içinde gruplayabilmenizdir.


11

Anonim sınıflarla, aslında "isimsiz" iç içe bir sınıf bildiriyorsunuz. İç içe sınıflar için, derleyici, bağımsız değişken olarak kullandığı tüm değişkenleri alacak bir yapıcı ile yeni bir bağımsız ortak sınıf oluşturur ("adlandırılmış" iç içe sınıflar için, bu her zaman orijinal / çevreleyen sınıfın bir örneğidir). Bu, çalışma zamanı ortamının iç içe sınıf kavramına sahip olmaması nedeniyle yapılır, bu nedenle iç içe geçmişten bağımsız bir sınıfa (otomatik) dönüştürme yapılması gerekir.

Örneğin bu kodu ele alalım:

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

Bu işe yaramaz, çünkü derleyicinin kaputun altında yaptığı şey budur:

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

Orijinal anonim sınıfın yerini, derleyicinin oluşturduğu bazı bağımsız sınıflar alır (kod tam değildir, ancak size iyi bir fikir vermelidir):

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

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

Gördüğünüz gibi, bağımsız sınıf paylaşılan nesneye bir referans tutar, java'daki her şeyin pass-by olduğunu unutmayın, bu nedenle EnclosingClass içindeki 'paylaşılan' referans değişkeni değişse bile, işaret ettiği örnek değiştirilmez ve ona işaret eden diğer tüm referans değişkenleri (anonim sınıftaki gibi: 1 TL'yi çevreleyen) bunun farkında olmayacaktır. Bu, derleyicinin sizi bu 'paylaşılan' değişkenleri nihai olarak bildirmeye zorlamasının ana nedenidir, böylece bu tür davranışlar zaten çalışan kodunuza girmez.

Şimdi, anonim bir sınıfın içinde bir örnek değişkeni kullandığınızda olan budur (sorununuzu çözmek, mantığınızı bir "örnek" yöntemine veya bir sınıfın yapıcısına taşımak için yapmanız gereken budur):

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

Derleyici kodu değiştireceğinden, bu derlenir, çünkü yeni oluşturulan 1 $ Enclosing sınıfı, EnclosingClass örneğinin somutlaştırıldığı örneğe bir referans tutacaktır (bu yalnızca bir temsildir, ancak gitmenizi sağlayacaktır):

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

Bunun gibi, EnclosingClass içindeki 'paylaşılan' referans değişkeni yeniden atandığında ve bu, Thread # run () çağrısından önce gerçekleştiğinde, iki kez yazdırılan "diğer merhaba" ifadesini görürsünüz, çünkü şimdi EnclosingClass $ 1 # çevreleyen değişken referans tutacaktır sınıfın bildirildiği nesneye bağlandığından, bu nesnedeki herhangi bir öznitelikte yapılan değişiklikler EnclosingClass $ 1 örnekleri tarafından görülebilir.

Konu hakkında daha fazla bilgi için, bu mükemmel blog gönderisini görebilirsiniz (benim tarafımdan yazılmamış): http://kevinboone.net/java_inner.html


Yerel değişken 'paylaşılan' değiştirilebilir bir nesne ise ne olur? Açıklamanıza göre 'nihai' ilan etmek de yardımcı olmaz, değil mi?
sactiw

Son olarak "paylaşılan" olarak bildirmek, nesnenin durumunu son değişken referanslarını değiştirmenize izin verir, ancak bu belirli örnek için işe yaramaz çünkü "paylaşılan" değişkenin değerini değiştiremezsiniz ( OP'nin istediği şeydir), anonim sınıflar içinde kullanabilirsiniz, ancak değeri değişmeyecektir (çünkü nihai olarak bildirilmiştir). Değişkenler ve tuttukları gerçek değerler arasındaki farkı fark etmek önemlidir (bunlar ilkel veya yığındaki nesnelere referans olabilir).
emerino

>>> ama değeri değişmeyecek Sanırım noktayı kaçırıyorsunuz yani son referans değişkeni değişken bir nesneyi gösteriyorsa, yine de güncellenebilir, ancak anonim sınıf sığ kopyayı oluşturur, bu nedenle değişiklikler anonim olarak yansıtılır sınıf. Başka bir deyişle, durum burada istenen şeydir. Burada OP'nin paylaşılan değişkeni (ilkel tip) değiştirme ve OP'nin değeri değiştirilebilir bir nesnenin altına sarması ve bu değişken nesneyi paylaşması gerekir.
sactiw

1
Elbette OP gerekli değeri değişken bir nesnenin altına sarabilir, değişkeni nihai olarak bildirebilir ve bunun yerine kullanabilir. Ancak, değişkeni geçerli sınıfın bir özniteliği olarak (yanıtta işaret edildiği ve açıklandığı gibi) bildirerek fazladan bir nesne kullanmaktan kaçınabilir. Değişken nesneleri zorlamak (sadece paylaşılan bir değişkenin değerini değiştirmek için dizileri kullanmak gibi) iyi bir fikir değildir.
emerino

7

Bu konuda yanıldığımda, nesneleri sadece kurucu aracılığıyla iç sınıfa geçiriyorum. İlkel veya değişmez nesneleri (bu durumda olduğu gibi) geçirmem gerekirse, bir sarıcı sınıf gerekir.

Düzenleme: Aslında, hiç anonim bir sınıf kullanmıyorum, ancak uygun bir alt sınıf:

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

2

Java Dil Belirtimi böyle söylediği için son olmayan değişkenlere başvuramazsınız. 8.1.3'ten:
"Kullanılan ancak bir iç sınıfta bildirilmeyen herhangi bir yerel değişken, biçimsel yöntem parametresi veya özel durum işleyici parametresi son olarak bildirilmelidir." Bütün paragraf.
Kodunuzun sadece bir kısmını görebiliyorum - bana göre yerel değişkenlerin modifikasyonunu planlamak garip bir fikir. İşlevden çıktığınızda yerel değişkenler ortadan kalkar. Belki bir sınıfın statik alanları daha iyi olurdu?


2

Sadece yazarların niyeti boyunca bir şeylerle başa çıkmak için bir şeyler yazdım . Yapabileceğim en iyi şeyi yapıcıya götürmek tüm nesneleri ve sonra uyguladığınız yöntemde bu yapıcı nesnelerini kullanmaktı.

Ancak, genel bir arabirim sınıfı yazıyorsanız, bir Nesne veya daha iyi bir Nesne listesi geçirmeniz gerekir. Bu, Object [] veya daha iyisi Object tarafından yapılabilir ... çünkü aramak daha kolaydır.

Örnek parçamı aşağıda görebilirsiniz.

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

}

Kutusundan çıkar çıkmaz bunu destekleyen Java kapaklarıyla ilgili şu gönderiye bakın: http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html

Sürüm 1, otomatik yayın ile son olmayan kapanmaların geçilmesini destekler:
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

Anonim bir sınıf içindeki bir yöntem çağrısındaki değeri değiştirmek istiyorsanız, o "değer" aslında bir Future. Yani, Guava kullanırsanız,

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

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

 return myvalue.get();

2

Fark ettiğim bir çözümden bahsedilmiyor (eğer kaçırmadım, lütfen beni düzelttiysem), bir sınıf değişkeninin kullanılmasıdır. Bir yöntem içinde yeni bir iş parçacığı çalıştırmaya çalışırken bu sorunla karşılaştım:new Thread(){ Do Something } .

doSomething()Aşağıdakilerden aramak işe yarayacaktır. Bunu beyan etmek zorunda değilsiniz final, sadece değişkenin kapsamını değiştirmeniz gerekir, böylece iç sınıftan önce toplanmaz. Tabii ki süreç çok büyük değilse ve kapsamı değiştirmek bir çeşit çatışma yaratabilir. Hiçbir şekilde son / sabit olmadığı için değişkenimi nihai yapmak istemedim.

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

}


1

son olmayan değişkene başvurmak için ClassName.this.variableName kullanın


1

sadece değişkeni dış sınıfın dışında bildirebilirsiniz. Bundan sonra, değişkeni iç sınıf içinden düzenleyebileceksiniz. Android'de kodlarken bazen benzer sorunlarla karşılaşıyorum, bu yüzden değişkeni küresel olarak ilan ediyorum ve benim için çalışıyor.


Bu gerçekten soruyu cevaplamıyor ... Bu yüzden aşağı indiriliyorsun.
Stuart Siegler

0

Eğer yapabilir lastPrice, priceObjectve priceanonim iç sınıfın alanlarını?


0

Ana endişe, anonim sınıf örneği içindeki bir değişkenin çalışma zamanında çözülüp çözülemeyeceğidir. Değişkenin çalışma zamanı kapsamı içinde olduğu garanti edildiği sürece bir değişkenin final yapılması zorunlu değildir. Örneğin, lütfen updateStatus () yönteminin içindeki _statusMessage ve _statusTextView değişkenlerine bakın.

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

benim için işe yarayan şey, sadece bu fonksiyonun dışındaki değişkeni tanımlamaktır.

Ana işlev bildirmeden hemen önce yani

Double price;
public static void main(String []args(){
--------
--------
}

Bu işe yaramaz, bir örnek değişkeni bildirirsiniz, kullanmak için ana yönteminizde bir örnek oluşturmanız gerekir. Daha spesifik olmanız veya statik değiştiriciyi 'price' değişkenine eklemeniz gerekir.
emerino

0

Değişkeni statik olarak bildirin ve className.variable kullanarak gerekli yöntemde referans alın


Non-static parameter cannot be referenced from a static context
stephen

@Shweta yerel değişkenleri ve yöntem parametreleri 'statik' olarak tanımlanamaz, dahası, yöntemlerin (yerel anonim sınıflar) içindeki sınıfların yöntemden sonra bile yerel değişkenlere ve yöntem parametrelerine erişmeye devam etmesine izin vermek için uygulanma şekliyle ilgilidir. yani 'son' kopyalarını verir ve bunları örnek değişkenleri olarak kullanır.
sactiw

0

Sadece başka bir açıklama. Aşağıdaki bu örneği düşünün

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

İşte Çıktı

m1 Tamamlandı

İş parçacığı t çalışıyor

İş parçacığı t çalışıyor

İş parçacığı t çalışıyor

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

Şimdi yöntem m1 () tamamlanır ve başvuru değişkenini null değerine atarız, Şimdi Dış Sınıf Nesnesi GC için uygundur, ancak çalışan Thread nesnesiyle (Has-A) ilişkisi olan İç Sınıf Nesnesi hala mevcuttur. Varolan Outer sınıfı nesnesi olmadan, mevcut m1 () yönteminin bulunma şansı yoktur ve mevcut m1 () yöntemi olmadan yerel değişkeninin var olma şansı yoktur, ancak Inner Class Object m1 () yönteminin yerel değişkenini kullanıyorsa, her şey açıklayıcıdır .

Bunu çözmek için yerel değişkenin bir kopyasını oluşturmalı ve daha sonra Inner sınıfı nesnesiyle öbeğe kopyalamalıyız, java'nın sadece son değişken için ne yaptığı, çünkü aslında sabit olmadıklarından değişmezler (Her şey sadece derleme zamanında gerçekleşir) çalışma zamanında değil).


-1

Yukarıdaki sorunu çözmek için farklı diller farklı kararlar alır.

Java için çözüm, bu makalede gördüğümüz gibidir.

C # için, çözüm yan etkilere izin verir ve referans ile yakalama tek seçenektir.

C ++ 11 için çözüm, programcının karar vermesine izin vermektir. Değer veya referans ile yakalamayı seçebilirler. Değere göre yakalanırsa, başvurulan değişken aslında farklı olduğundan hiçbir yan etki oluşmaz. Referans olarak yakalanırsa, yan etkiler ortaya çıkabilir, ancak programcı bunu fark etmelidir.


-2

Çünkü değişkenin nihai olmaması kafa karıştırıcıdır, çünkü anonim sınıftaki değişiklikler alınmayacaktır.

Sadece 'price' ve 'lastPrice' değişkenlerini sonlandırın.

-- Düzenle

Hata! Ayrıca, açıkça işlevinize onlara atamamanız gerekir. Yeni yerel değişkenlere ihtiyacınız olacak. Her neyse, şimdiye kadar birinin sana daha iyi bir cevap verdiğinden şüpheleniyorum.


2
sadece kafa karıştırıcı değil - düpedüz yanlış, bu nedenle derleyici buna izin vermiyor.
Chii

Ama sonra ihtiyacım olduğunda değerleri nasıl değiştirebilirim?
Ankur

Sadece kafa karıştırıcı olduğu için değil; Bunun nedeni Java'nın kapanmaları desteklememesidir. Cevabımı aşağıda görebilirsiniz. @Ankur: main () içindeki yerel değişkenler yerine anonim sınıf nesnesinin değişkenleri üye değişkenlerini yapabilirsiniz.
Jesper

Onları değiştiriyor, bu yüzden nihai olamazlar.
Robin

Fiyat ve lastPrice kesin olsaydı, onlara verilen ödevler derlenmeyecekti.
Greg Mattes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.