Home > Software engineering >  How can I access a inner class in a Parent class from within a Child class?
How can I access a inner class in a Parent class from within a Child class?

Time:10-18

Dears,

I have a Parent and Child class:

public class Parent{

    protected class Inner{
    
    }
}

public class Child extends Parent{

    protected class Inner{
    
    }
}

And I want to use the Inner Child classes in the parent:

myMethod(Inner inner)

Is setting the Inner class to protected enough to achieve this?

CodePudding user response:

No,

you need to extend the Inner class in the Child class like this:

public class Child extends Parent{

    protected class Inner extends Parent.Inner{

That way your myMethod(Inner inner) will recognize the Child classes as children of the Parent.Inner class. Otherwise the Child class's Inner will not be of the type Parent.Inner (and will not be recognized as a subclass of that class (or could be used in the same method)).

CodePudding user response:

In your provided code, the two classes named Inner are utterly, completely unrelated. You just.. have two classes that so happen to have the same name. It's like java.awt.List and java.util.List: Yes, same name, but this means nothing at all as far as equivalence (they are as different as guns and grandmas) and access rules (the access rules are what they are; that they share a name has no bearing on it).

To name them 'properly', you can write Child.Inner and Parent.Inner which differentiates them. Just writing Inner will be interpreted by javac as one or the other depending on imports and context (inside the braces that go with Child extends Parent {}, it is interpreted as Child.Inner due to that being a same-file sibling, unless you have an explicit import; most other places it'll either not compile or be interpreted as Parent.Inner). Given that these are somewhat esoteric rules, best bet is to just not write just Inner in such a case, and always be explicit. "But shorter code" is a good rule of thumb but rules of thumb are called that because they aren't always right. Otherwise they'd just be called "The rule", no need to involve thumbs.

But, before doing that, why are you have 2 unrelated classes with the same name in the same project in the first place? That's confusing even if everybody writes out a full name to try to avoid confusion.

What is your actual intent here?

I want Child.Inner to be a subclass of Parent.Inner, mirroring Child and Parent's relationship

Then write that:

public class Child extends Parent {
  public class Inner extends Parent.Inner {}
}

I'd still strongly consider picking different names here. Perhaps public class ChildInner - obviously Inner is just a placeholder name here and not what's really in your project, so I can't give much advice on what name to pick. Just that 'same name' is a bad idea.

Your Child.Inner has a hidden-named instance of Child available to it, which is a more specific kind of Parent, and it is itself a more specific kind of Parent.Inner, meaning every method in any of the 4 classes is available to it. If Parent or Child has a method named x() and Parent.Inner or Child.Inner also has a method named x(), you can differentiate using this syntax:

Child.this.x();

But, again, why would you confuse things like this by using the same name so many times?

I just want the code in Child to be able to access methods and fields from Parent.Inner.

Then do not make a second class, your intent is clearly not to have 2 inner classes in the first place. Every instance of Child is a more specific kind of Parent, so you can make new instances of Parent.Inner whose 'enclosing instance' is in fact an instance of Child, no problem.

In Child.java:

Inner inner = new Inner();

And outside of that:

Parent.Inner inner = someInstanceOfChild.new Parent.Inner();

Naturally, as the code in Parent's Inner has no idea if the instance of the enclosing class is an instance specifically made with new Parent() or an instance of some more specific type, e.g. new Child(), no method that exists in only in Child can be invoked, but you can instanceof and cast your outer this instance:

if (Parent.this instanceof Child) {
    Child c = (Child) Parent.this;
    c.methodOnlyInChild();
}

works just fine.

  • Related