tags:

views:

3625

answers:

4

Sorry for the bad title, but I couldn't think of a better one.

I'm having a class A and a class B which is kind of a sub class of A, like so:

(Is there actually a correct name for it? Isn't "sub class" reserved for inheritance?)

class A {
    int i = 0;
    class B {
        int j = 1;
    }
}

class Test {
    public static void main() {
        A a = new A();
        B b = a.new B();
        A c = ??? b ??? // get "a" back
    }
}

From B every property of A can be accessed, therefore both, a.i and b.i, return 0. Now, I'm wondering whether it's somehow possible to retrieve the original object of type A out of b, as b contains everything that a contains? Simple casting apparently doesn't do the trick.

Second one:

class A {

    void print() {
        System.out.println("This is class A.");
    }

    class B {
        void print() {
            // <--- How to access print() of class A (like this.A.print() or smth)? 
            System.out.println("This is class B.");
        }
    }
}

You could alternatively also provide me with some good resources on this topic, as I've been too stupid to find a good one so far.

Thanks in advance. :)

+2  A: 

[Edit: My answer is appropriate for C# programmers, but I can't guarantee that its applicable to Java.]

B is an inner class, not a subclass of A. Additionally, B does not hold an instance of A, so your code as is cannot return any instance of A.

You need to restructure your classes as follows:

class A
{
    public class B
    {
       public A Parent;
       public B(A parent)
       {
          this.Parent = parent;
       }
    }
}

Now your B class has a field 'Parent' which returns its parent. You can use these classes as follows (this is C# syntax, because I don't know if Java has a different syntax for instantiating inner classes):

public static void Main(String[] args)
{
    A parent = new A();
    A.B child = new A.B(child);
    A backToParent = child.Parent;
}

Of course, creating your B class in this way seems little funny: technically, you can pass in any parent. It would probably be better to rewrite your A class with a method which returns a B:

class A
{        
    public class B
    {
       public A Parent;
       public B(A parent)
       {
          this.Parent = parent;
       }
    }

    public B getChild()
    {
        return new B(this);
    }
}

public static void Main(String[] args)
{
    A parent = new A();
    A.B child = A.getChild();
    A backToParent = child.Parent;
}
Juliet
In fact, it does hold an instance of A. See also: http://stackoverflow.com/questions/309737/how-to-refer-to-the-outer-class-in-another-instance-of-a-non-static-inner-class However, thanks for your answer. The way you described is certainly another solution.
codethief
It seems "inner class" referes to a different concept than in Java (approximately what Java would call "nested class").
Tom Hawtin - tackline
+9  A: 

There doesn't seem to be a way to access the outer class from outside. But you can do it like this:

class A {
    int i = 0;
    class B {
        final A outer = A.this;
        int j = 1;
    }
}

class Test {
    public static void main() {
        A a = new A();
        A.B b = a.new B();
        A c = b.outer // get "a" back
    }
}

ClassName.this will be the instance of the outerclass associated with the instance of an inner class.

Johannes Schaub - litb
I think B b = ... is wrong. You cannot declare a ref of type B without using A. A.B b = ... Would be better..
OscarRyz
yes i thought so too
Johannes Schaub - litb
I'd make the declaration `final A outer = A.this;` to be on the safe side
Bill Michell
Bill, thanks corrected
Johannes Schaub - litb
A more elegant solution is to provide a method like outer() to return A.this to save adding a field.
Peter Lawrey
Adding a field not only wastes space but create a circular dependency which is much harder for the GC to clean up.
Peter Lawrey
@Peter Lawrey: adding final A outer = A.this to inner class B happens implicitly anyway. Johannes simply makes it explicit. Check disassemled A$B.class without final A outer variable:>javap A$BCompiled from "A.java"class maxim.A$B extends java.lang.Object{ int j; final maxim.A this$0; maxim.A$B(maxim.A);}
Max
@Max, I aggree that you get a this$0 field for free which is why you don't need the explicit field to do what java does for you anyway. Not sure why making the field explicit any clearer than using a method to return the same value.
Peter Lawrey
+3  A: 

You can access it with the ParentClass.this syntax from within the inner class.

e.g.

public class Outter
{
    class Inner {
        public Outter getOutter()
        {
            return Outter.this;
        }
    }

    public Inner getInner(){
        return new Inner();
    }
}

class Runner{
    public static void main(String[] args){
        Outter out = new Outter(); 
        Outter.Inner inner = out.getInner();

        System.out.println(inner.getOutter().toString());
    }
}
madlep
+1  A: 

this seemed to work for me

class A {
    int i = 0;
    class B {
        int j = 1;
    }
}

class Test {
    public static void main() {
        A a = new A();
        A.B b = a.new B();
        A c = (A)b.getClass().getDeclaredField("this$0").get(b);
    }
}
newacct