views:

1364

answers:

6

If I have an instance of an inner class, how can I access the outer class from code that is not in the inner class? I know that within the inner class, I can use Outer.this to get the outer class, but I can't find any external way of getting this.

For example:

public class Outer {
  public static void foo(Inner inner) {
    //Question: How could I write the following line without
    //  having to create the getOuter() method?
    System.out.println("The outer class is: " + inner.getOuter());
  }
  public class Inner {
    public Outer getOuter() { return Outer.this; }
  }
}
+9  A: 

There is no way, by design. If you need to access the outer class through an instance of the inner one, then your design is backwards: the point of inner classes is generally to be used only within the outer class, or through an interface.

Michael Borgwardt
That was my thought too, but I can't seem to find any documentation which addresses this limitation. If you can find anything official I'll gladly accept this answer.
Kip
It's not an explicit "limitation" - why should there be documentation about the ABSENCE of a particular (rather obscure) feature?
Michael Borgwardt
15.8.3 and 15.8.4 covers it. "Any lexically enclosing instance can be referred to by explicitly qualifying the keyword this." In the question's case, it isn't a lexically enclosing instance.
Tom Hawtin - tackline
+4  A: 

The bytecode of the Outer$Inner class will contain a package-scoped field named this$0 of type Outer. That's how non-static inner classes are implemented in Java, because at bytecode level there is no concept of an inner class.

You should be able to read that field using reflection, if you really want to. I have never had any need to do it, so it would be best for you to change the design so that it's not needed.

Here is how your example code would look like when using reflection. Man, that's ugly. ;)

public class Outer {
    public static void foo(Inner inner) {
        try {
            Field this$0 = inner.getClass().getDeclaredField("this$0");
            Outer outer = (Outer) this$0.get(inner);
            System.out.println("The outer class is: " + outer);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public class Inner {
    }

    public void callFoo() {
        // The constructor of Inner must be called in 
        // non-static context, inside Outer.
        foo(new Inner()); 
    }

    public static void main(String[] args) {
        new Outer().callFoo();
    }
}
Esko Luontola
That's (IIRC) compiler dependent, and you'll need a setAccessible in general.
Tom Hawtin - tackline
I think (too lazy to look up the spec) even the naming of that field is compiler dependent, so you *could* possibly run into problem if you try that hack with another compiler.
Joachim Sauer
+4  A: 

What's wrong with adding a getter when you need to access the outer class? That way you can control whether access is allowed or not.

starblue
+1  A: 

Can't you just do something like this:

public static class Inner { // static now
    private final Outer parent;

    public Inner(Outer parent) { this.parent = parent; }

    public Outer get Outer() { return parent; }
}
Outlaw Programmer
+1  A: 

If you've got a (non-static) inner class, then you're by definition working with something that only functions inside the enclosing context of the outer class. So to get a handle to the inner class, you'd already have to have retrieved it through the outer instance. So the only way I can see to get to the point where you'd need an accessor like that is to have grabbed the inner through the outer ref and then lost or discarded the outer instance reference.

For example:

public class Outer{ 
   public class Inner {
   }
}

public class UsesInner{
 Collection<Outer.Inner> c = new ArrayList<Outer.Inner>();
}

Now the only way you can populate c is by creating Outer() instances. I'd be curious to see a useful purpose for something like this.

Steve B.
Honestly, I can't think of a good reason either. I just ran across it trying to answer this question: http://stackoverflow.com/questions/763359/validating-instances-of-inner-classes/763504 In that case, he wanted to make sure he had an inner class of a specific instance of the outer class. I suggested in another answer that he should just define the method in the inner class so that it wouldn't be a problem. But, again, I was curious if there way to do it.
Kip
+1  A: 

Here is one reason you may want this behavior: You have the inner class instance and need to access a method defined in the outer class using reflection.

For the record, "inner.getClass().getDeclaredField("this$0")"works. Since the field is private, you also need to call field.setAccessible(true).

Rich MacDonald