할 수 없는 참조를 비 최종 변수 내 안에 정의된 클래스가 다른 방법

StackOverflow https://stackoverflow.com/questions/1299837

문제

편집:내가 값을 변경해야 할 여러 개의 변수들은 여러 번 실행 관련 타이머입니다.나 업데이트 유지해야하는 값으로 모든 반복 타이머입니다.할 수 없습 값을 설정하는 최종로는 못하게 하는 값을 업데이트 그러나 나는 오류를 설명하에서 초기 아래 질문:

나는 이전에 작성된 것은 아래와 같습니다.

나는 오류"참조할 수 없습니다 비 최종 변수 내 안에 정의된 클래스가 다른 방법".

이것은 일어나고 두 번이라고 가격에 그리고 가격이라고 priceObject.왜 이것을 얻을 문제입니다.내가 이해하지 못하는 내가 왜 필요한 최종 선언입니다.또한 볼 수 있다면 그것이 무엇인지 내가 하려고 해야할지,어떻게 해야 할까 이 문제를 해결하기 위해서.

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);
}
도움이 되었습니까?

해결책

자바를 지원하지 않는 진정한 폐쇄, 도를 사용하여 익명의 클래스를 사용하는 것 같은 여기서(new TimerTask() { ... }')는 다음과 같은 종류의 폐쇄입니다.

편집 - 참조 아래의 댓글-다음은 올바른 설명으로 KeeperOfTheSoul 습니다.

이런 이유로 그것은 작동하지 않:

변수 lastPrice 와 가격은 현지 변수에 main()메소드가 있습니다.체로 만드는 익명 등 수 있는 마지막까지 후 main() 방법을 반환합니다.

main() 메서드를 반환,지역 변수(예: lastPriceprice)됩니다 스택에서,그래서 그들은 존재하지 않습니다 더 이상 한 후에 main() 반환합니다.

그러나 익명의 클래스의 객체 참조를 이러한 변수입니다.것게 잘못하는 경우 익명의 클래스의 객체에 액세스하려고 시도한 후에는 변수들이 정리되었습니다.

lastPriceprice final, 그들은 정말 변수,더 이상 하지만 상수입니다.컴파일할 수 있는 다음 단체의 사용 lastPriceprice 에 익명으로 클래스의 값을 상수(컴파일 시간에는 물론),그리고 당신은 당신의 문제에 액세스하는 존재하지 않는 변수를 더 이상입니다.

다른 프로그래밍 언어를 지원하는 폐쇄에 의해 그것을 할 사람들을 치료하는 변수는 특별히 확인함으로써 그들은 파괴되지 않는 경우 방법이 종료되도록 폐쇄 액세스할 수 있는 변수입니다.

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

다른 팁

를 피하는 이상한 부작용과 폐쇄 자바에서 변수를 참조하는 익명의 대리자를 표시해야합니다 마지막으로,그래서를 참조 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 으로 최종 통화합니다.틱에서 타이머입니다.

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

에만 액세스할 수 있다 최종 변수를 포함하는 클래스에서 사용하는 경우 익명의 클래스입니다.따라서을 선언해야 합 변수를 사용되는 최종(는 당신을 위한 선택권 이후 변경 lastPrice가격다),또는 사용하지 않는 익명의 클래스입니다.

그래서 옵션을 만들 수 있는 실제의 내부 클래스에서 전달할 수 있는 변수들을 사용하여 일반 패션

또:

이(그리고 내 생각에 추)해킹에 대한 귀하의 lastPrice가격 는 변수를 선언하는것처럼 그렇

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

과에서 당신의 익명 클래 값을 설정할 수 있습 다음과 같이

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

좋은 설명을 위해할 수 없습니다 왜 당신은 무엇을 하려고 하는 이미 제공합니다.는 솔루션으로,어쩌면 사항:

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

처럼 보인다 아마 당신이 할 수 있는 더 나은 디자인 보다는,하지만 아이디어는 그룹화할 수 있습 업데이트 변수의 내부에는 클래스를 참조하는 변하지 않습니다.

익명으로스,당신은 실제로 선언"이름"중첩된 클래스입니다.중첩된 클래스,컴파일러에 새로 생성 독 공공급과 생성자 그리고 모든 변수 사용으로 인수(예"이름이"중첩된 클래스,이것은 항상 인스턴스의 원/바깥쪽 클래스).이렇기 때문에 런타임 환경의 개념이 없 중첩된 클래스는 그래서 요구하는 것(자동)에서 변환을 중첩하는 독립 클래스입니다.

이 코드 예를 들어:

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

당신이 볼 수 있는 독립형을 보유 하는 클래스를 참조하여 공동체,기억하는 모든 것에서 자바 패스 에 의하여 가치,그래서 그는 경우에도 참조 변수는'공유'에 EnclosingClass 가 변경되는 인스턴스는 수정되지 않으며,모든 다른 변수를 참조를 가리키(처럼에서 하나 익명의 클래스:바깥쪽$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);
    }
}

이 컴파일되기 때문 컴파일러의 코드를 수정합니다,그래서 새로운 생성되는 클래스를 둘러싸$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);
    }
}

다음과 같이,때 참조 변수는'공유'에 EnclosingClass 가져온 그리고 이런 일이 발생하기 전에 전화를 실#run(),당신은"다른 안녕하세요"두 번을 인쇄하기 때문에,지금 EnclosingClass$1#둘러싸 변수를 유지에 대한 참조를 객체의 클래스가 그것을 선언했다,그래서 변경 사항을 어떤 특성에는 개체의 표시의 인스턴스 EnclosingClass$1.

에 대한 주제에 대한 자세한 정보를 볼 수 있습니다,당신이 우수한 블로그 포스트(작성되지 않은 나에 의하여): http://kevinboone.net/java_inner.html

면 나는 우연히 이 문제 난 그냥 통과하는 객체의 내부 클래스를 통해 생성자입니다.가 필요한 경우에는 전달하는 기본 형식 또는 변경되지 않는 객체(이 경우),랩퍼 클래스가 필요합니다.

편집:실제로,나는 사용하지 않는 익명의 클래스에서는 모든하지만,적절 한 서브 클래스:

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

할 수 없는 참조를 비 최종기 때문에 변수는 Java 언어 명세는 이렇게 말합니다.에서 8.1.3:
"어떤 지역 변수,형식적인 방법을 매개 변수 또는 예외 처리 매개 변수는 사용하지만에 선언된 내부 클래스 선언해야 합니다." 전체 단락에 있습니다.
나의 코드-나에 따라 일정의 수정 지역 변수가 이상한 생각입니다.지역 변수가 존재하지 않을 떠날 때는 기능입니다.어쩌면 정적 필드 클래스의 것이 좋을까?

나는 그냥 무언가를 썼다면 핸들 따라 뭔가 저자는 기도.내가 발견 할 수 있는 최고의 일이었자 생성자를 취할 모든 객실에서 당신의 구현 방법을 사용하여 그 생성자체입니다.

그러나,작성할 경우에는 일반 인터페이스 클래스,당신은 전체,또는 더 나은 목록이다.이 할 수 있는 객체[]또는 더 나은, 체... 기 때문에 그것은 호출하는 것이 더 쉽습니다.

나의 예는 조각습니다.

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

}

해당 게시물을 참조하시기 바랍니다에 대한 자바 폐쇄를 지원하는 이의 시스템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/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));
        }
    });

당신이 원하는 값을 변경 방법으로 통화 내에서 익명의 클래스는"value"제 Future.그래서 사용하는 경우,당신은 구아바를 작성할 수 있습니다

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

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

 return myvalue.get();

하나의 솔루션을 발견했 언급하지 않으면(지 않는 한 나는 그것을 놓쳤다면,나는 저를 수정하시기 바랍니다),사용은 클래스의 변수입니다.실행으로 이 문제점을 실행하는 새로운 실내법: new Thread(){ Do Something }.

전화 doSomething() 에서 다음과 같은 일할 것이다.당신이하지 않는 반드시 그것을 선언 final, 그냥을 변경할 필요가 범위의 변수 그래서 그것은 수집하지 않기 전에 innerclass.이것은 물론 귀하의 프로세스는 거대하고 변경의 범위를 만들 수 있습니다 어떤 종류의 충돌이 있습니다.지 않았을 만들고 싶어 내는 변수 최종으로 어떠한 방식으로 최종/상수입니다.

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

}

는 경우는 변수에 필요한 최종할 수 없습니다 그 다음에 할당할 수 있는 변수 값을 다른 변수 및 최종 사용할 수 있도록 그것을 대신 합니다.

사용 ClassName.다.변수명을 참조 non-최종 변수

할 수 있는 단지 외부에서 변수를 선언해야 합니 외부 클래스입니다.이 후,당신은 편집 할 수 있습니다면 변수 내에서 내부 클래스입니다.나는 때로는 비슷한 문제에 직면 코딩하는 동안 안드로이드에 그래서 나는 변수를 선언합으로 글로벌하고 그것이 나를 위해 작동 합니다.

lastPrice, priceObject, 고 price 의 분야에 익명의 내부 클래스?

주요한 관심사는 여부 변수가 내부에 익명의 클래스의 인스턴스를 해결할 수 있습니다.지 않음에도 불구하고 만들 변수 최종로 보장하는 변수가 내부에 실시간 범위가 있습니다.예를 들어,참조하시기 바랍 두 변수 _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);

                }

            });
        }
    }

}

어떤 나를 위해 일하는 그냥 변수를 정의 밖에 이 기능이 있습니다.

기 전에 주요 기능을 선언 즉

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

변수를 선언합적으로 정적이며 참조에 필요한 방법을 사용하여 클래스 이름.변수

그냥 다른 설명이 있습니다.이것을 고려면 아래 예제

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

스레드를 실행 t

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

이제 방법 m1()를 완료하고 우리는 할당을 참조 변수 o null,이제 외래 물체에 대한 자격 GC 하지만 내면의 클래스의 객체가 여전히 존재하는가(이-)의 관계는 실체가 실행 중입니다.지 않고 기존의 외부 클래스 개체할 기회가 없다의 기존의 m1()메서드지 않고 기존의 m1()메소드의 기회가 없이 기존의 지역 변수 하지만 만약 내부 클래스 객체를 사용하여 지역 변수의 m1()메소드 그 모든 것은 자명하다.

이러한 문제를 해결하기 위하여야의 복사본을 만들어 지역 변수하고 다음을 복사본을 다음으로 힙 내부 클래스 객체는 무엇 java 는 대만 최종 변수하지 않기 때문에 그들은 변수는 실제로 그들은 같은 상수(에서 발생하는 모든 컴파일 시간이 단지에서 런타임).

문제를 해결하기 위,다른 언어로 서로 다른 결정을 내린다.

Java,해결책은 무엇으로 우리는 이 문서에서.

C#,이 솔루션은 허용 부작용에 의해 캡처를 참조은 옵션입니다.

C++11,솔루션 수 있도록 프로그래머들에게 결정합니다.그들이 선택할 수 있습을 캡처하여 값이나 참조에 의해.면 캡처하여 가치,부작용이 없을 것이기 때문에 발생할 가 참조하는 변수는 실제로 다릅니다.면 캡처를 참조 부작용이 발생할 수 있습니다 하지만 프로그래머로 해야 그것을 실현합니다.

기 때문에 혼란스럽다면 변수가 마지막으로,이를 변경하지 않을 것이 포착에서 익명의 클래스입니다.

그들에게 변수는'가격'과'lastPrice'최종입니다.

--편집

죄송합니다,당신은 또한 필요하지 않은 할당,그들에게 분명히,에서 당신의 기능입니다.해야 합 새로운 지역 변수.어쨌든,내가 의심스러운 사람이 주신은 더 나은 대답이다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top