Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the recommended/correct way to access fields in an inner class?

Suppose we have this class and its inner class:

/* Outer.java */
public class Outer {
    private static class Inner {
        private final Object foo;

        public Inner(Object foo) {
            this.foo = foo;
        }

        public Object getFoo() {
            return foo;
        }
    }

    Inner inner = parse(/* someMistery */);

    // Question: to access foo, which is recommended?
    Object bar = inner.getFoo();
    Object baz = inner.foo;
}

I am surprised that inner.foo works.

Since foo is private, it can be accessed only through getFoo(), right?

like image 784
XoXo Avatar asked May 12 '15 19:05

XoXo


People also ask

How do I access an inner class from another class?

To instantiate an inner class, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax: OuterClass. InnerClass innerObject = outerObject.

What are the rules for inner class?

Rules of Local Inner Class:The scope of the local inner class is restricted to the block they are defined in. A local inner class cannot be instantiated from outside the block where it is created in. Till JDK 7, the Local inner class can access only the final local variable of the enclosing block.

What is the correct syntax for member inner class?

It is also known as regular inner class. It can be declared with access modifiers like public, default, private, and protected. The syntax to declare member inner class in Java is like this: Syntax: class Outer { // A member inner class named Inner.

What Can inner classes access?

It can access any private instance variable of the outer class. Like any other instance variable, we can have access modifier private, protected, public, and default modifier. Like class, an interface can also be nested and can have access specifiers.


1 Answers

Since foo is private, it can be accessed only through getFoo(), right?

In this case, Outer has access to it too, because Inner is a member of Outer.

6.6.1 says:

[If] the member or constructor is declared private, [then] access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member or constructor.

Note that it's specified to be accessible within the body of the top level class that encloses the declaration.

This means, for example:

class Outer {
    static class Foo {
        private Foo() {}
        private int i;
    }
    static class Bar {{
        // Bar has access to Foo's
        // private members too
        new Foo().i = 2;
    }}
}

Whether to use a getter or not is really a matter of taste. The important realization here is that outer classes have access to the private members of their nested classes.

As a recommendation, I would personally say:

  • If the nested class is private (only the outer class has access to it), I wouldn't bother even giving it a getter unless the getter does a computation. It's arbitrary, and somebody else can come along and choose not to use it. If the styles are mixed, the code has a vagueness. (Do inner.foo and inner.getFoo() really do the same thing? We have to go waste time examining the Inner class to find out.)
  • But you could go through a getter anyway if that's the style you are comfortable with.
  • If the nested class isn't private, use the getter so the style is uniform.

If you really want to hide the private members, even from the outer class, you can use a factory with a local or anonymous class:

interface Nested {
    Object getFoo();
}

static Nested newNested(Object foo) {
    // NestedImpl has method scope,
    // so the outer class can't refer to it by name
    // e.g. even to cast to it
    class NestedImpl implements Nested {
        Object foo;

        NestedImpl(Object foo) {
            this.foo = foo;
        }

        @Override
        public Object getFoo() {
            return foo;
        }
    }

    return new NestedImpl(foo);
}

As a pedantic note, your static class Inner {} is technically a static nested class, not an inner class. class Inner {} (without static) would be an inner class.

This is specifically defined to be so:

The static keyword may modify the declaration of a member type C within the body of a non-inner class or interface T. Its effect is to declare that C is not an inner class.

like image 141
Radiodef Avatar answered Nov 09 '22 03:11

Radiodef