-1

When compiling the following code, i got compile error:

MadScientist.java:27: Error: local variable timeTraveler is accessed from within inner class; needs to be declared final

import java.util.*;

interface TimeTravelCallback {
    void leaped(int amount);
}
interface TimeTraveler {
    void adjust(int amount);
}
class LinearTimeTraveler implements TimeTraveler {
    @Override public void adjust(int amount) {

    }
}

public class MadScientist {

    public static void main(String[] args) {

    MadScientist madScientist = new MadScientist();
    TimeTraveler linearTimeTraveler = new LinearTimeTraveler();
    madScientist.experiment(linearTimeTraveler);
    }

    public void experiment(TimeTraveler timeTraveler) {
        TimeTravelCallback cb = new TimeTravelCallback() {
            @Override public void leaped(int amount) {
                timeTraveler.adjust(amount); //error message
            }
        };
        cb.leaped(20);
    }
}

If I change

public void experiment(TimeTraveler timeTraveler) {

to

public void experiment(final TimeTraveler timeTraveler) {

then it works.

Is there any other fix without adding the 'final' at the method parameter?

Anptk
  • 1,125
  • 2
  • 17
  • 28
loop
  • 219
  • 2
  • 5
  • 12
  • http://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class – nano_nano Mar 02 '15 at 07:20
  • *Is there any other fix without adding the 'final' at the method parameter?* - No. What is the problem in declaring it as *final*?. It will still be *mutable*. – TheLostMind Mar 02 '15 at 07:20
  • @TheLostMind: Well, the parameter itself won't be mutable - the OP won't be able to change its value. But it will still refer to a mutable object. – Jon Skeet Mar 02 '15 at 07:23
  • Note that in Java 8 I believe this would be implicitly final, so it would be okay. – Jon Skeet Mar 02 '15 at 07:24
  • @JonSkeet - Yes. The *reference* will be *final* (not sure if I should use the term *immutable* for references). but the object will be *mutable*. And Yes, in Java -8, if the OP doesn't doesn't modify this object in later part of his code, it will be *effectively final* and he won't get this warning :) – TheLostMind Mar 02 '15 at 07:26
  • @TheLostMind: Again, I'd say it's the *parameter* that's final, not the reference. The reference is just a value. When you change the value of the parameter, that's not making a change to the reference - it's putting a different reference in the place of the old one. But I think we agree on the actual behaviour... – Jon Skeet Mar 02 '15 at 08:08
  • @JonSkeet - *Again, I'd say it's the parameter that's final, not the reference* - Please help me out here. Doesn't *parameter* mean *reference*?. I mean the parameter is just another reference to the same object which is passed to a method.. right?. When we do `Object o = new Object();` and then call `void someMethod(Object obj)` then `o` and `obj` are 2 different references which will point to the same Object when we do `someMethod(o)`. *the reference is just a value* --> *The reference points to a value*? – TheLostMind Mar 02 '15 at 08:31
  • @TheLostMind: No, parameter doesn't mean reference. The parameter is a variable. The *value* of the parameter is a reference. Suppose we have a parameter `int x`. The value of `x` is an `int`, but `x` itself is a variable. In your example, `o` and `obj` are two separate variables, whose values are the same references. – Jon Skeet Mar 02 '15 at 09:32
  • @JonSkeet - Ok.. So you are trying to say that here there will be 2 parameters with the same reference . And one parameter amongst them is *final*. right? – TheLostMind Mar 02 '15 at 10:00
  • No, `o` isn't a parameter - it's just a local variable. It's used as the argument to `someMethod`, which has a single parameter (`obj`). The initial value of `obj` will be the same as the value of `o`. – Jon Skeet Mar 02 '15 at 10:08

2 Answers2

0

If you want to do any operation on your final variable passed to your method then use any collection api like List.

public void experiment(final List<TimeTraveler> timeTraveler) {

 }

Now, you can modify the value inside your list.

atish shimpi
  • 4,873
  • 2
  • 32
  • 50
0

If you don't want to add final, you should create a constructor in you inner class TimeTravelCallback and pass the timeTraveler object to this constructor :

    TimeTravelCallback cb = new TimeTravelCallback(timeTraveler) {
       public TimeTravelCallback(TimeTraveler timeTraveler){
          this.timeTraveler = timeTraveler;
       } 
        @Override public void leaped(int amount) {
            timeTraveler.adjust(amount); //error message
        }
    };
Anthony
  • 429
  • 1
  • 4
  • 10