views:

341

answers:

5

To access the field x of an outer class A from an inner class B, I realize that you can use "A.this.x". But what if the outer class is also anonymous? For example,

public class Main1 {
    public static void main(String[] args) {
        Comparable c1 = new Comparable(){
            int x = 3;
            public int compareTo(Object o) {
                Comparable c2 = new Comparable(){
                    int x = 4;
                    public int compareTo(Object o) {
                        return x;  // <-- THIS LINE
                    }
                };
                return c2.compareTo(o);
            }
        };
        System.out.println(c1.compareTo(null));
    }
}

When this code is run, the value of 4 is printed because that is the value of c2's field x. However, I would like to change the line marked "THIS LINE" so that it returns the outer class's x (that is, c1's field x, with the value 3). If the outer class (that is, c1's class) were a named class A, then I could replace

return x;

with

return A.this.x;

But since the outer class is also anonymous, I don't have a name to use.

Question: Is there a way to modify the line labeled "THIS LINE" so that it refers to c1's field x rather than c2's, without changing the anonymous classes into named classes?

I realize this code is really ugly and it is not good programming style to use anonymous classes this way, but the code is being generated by another program, and this is the easiest way to implement the generator.

+4  A: 

I would avoid hiding the other variable by choosing a name other than x.

Outlaw Programmer
A: 

I believe you will have to declare the fields final -- the code you have there compiles only because of the shadowing you are complaining about. Not true.

This looks like a classic case where something like Lisp's gensym will make things easier. In other words, have the code generator use different identifiers for those variables -- e.g. x1 and x2.

Steven Huwig
The fields don't need to be final; that's only for parameters/local variables. If he called the outer field 'y', he could access it from the innermost class.
Outlaw Programmer
+1  A: 

The simple answer is to not shadow the variables:

public static void main(String[] args) {
 Comparable c1 = new Comparable() {
  int x = 3;
  public int compareTo(Object o) {
   Comparable c2 = new Comparable() {
    //changed this name
    int y = 4;
    public int compareTo(Object o) {
     return x;
    }
   };
   return c2.compareTo(o);
  }
 };
 System.out.println(c1.compareTo(null));
}

Output:

3

Given that you are working with generated code, is this an option for you?

matt b
+1  A: 

AFAIK there's no way to achieve what you want. If you can change the code (as you appear to be able to) but don't want to change them into named classes, can you just change the name of the variables so you don't have scope issues? You should rename them for clarity anyway

MrWiggles
+1  A: 

Classes are anonymous -- nameless. No way of accessing their fields using name reference. There's no name.

Boris Pavlović