How can I make fields in nested class real private?

352 views Asked by At

I have a nested (static) class with a private field and a setter method for this field.

public class Outer{
    private static class Inner{ // List node
        private String fieldA;

        // ...other members...

        public void setA(String fieldA)
        {
            //.. do importent stuff before setting fieldA
            this.fieldA = fieldA;
        }
    }
}

Now we had a bug because the fieldA is accessed directly (and not by setter method setA) by Outer class although the field fieldA is private. How can I enforce developers to use the setter method instead of directly accessing the field?

I have read the related topic Access modifiers inside a private static nested class in Java that states that it is by design. But is there a workaround to ensure using setter method by outer class?

1

There are 1 answers

2
kapex On BEST ANSWER

If the class must not be moved to outside of Outer, you should define an interface for Inner and use only that. If you have only few instances and this is not a performance critical point of your application, you could just create anonymous implementations of that interface. The class isn't static anymore but at least it's a short and readable solution.

private static interface Inner {
    void setA(String a);
}

private  static Inner createInner() {
    return new Inner() {
        private String a;

        @Override
        public void setA(String a) {
            this.a = a;
        }
    };
}

If you want to keep the class static, I don't see many options to hide anything from the outer class. You can try to make it more obvious that the inner class should be used carefully.

It looks a bit strange, but you could move the implementation into the interface like in the following example - that doesn't really prevent anyone from using Inner.InnerImpl, but it should imply that the class InnerImpl belongs to Inner and is not be used directly.

public class Outer{

    private static interface Inner {

        static class InnerImpl implements Inner {

            private String a;

            @Override
            public void setA(String a) {
                this.a = a;
            }
        }

        void setA(String a);

    }

    // either instantiate directly or again wrap it in a `createInner()` method 
    // Inner inner = new Inner.InnerImpl();
}

Actually here is another quite simple option. I think for this special case you could justify introducing a new naming convention to avoid accidental use of properties.

private static class Inner {

    private String _a;

    public void setA(String a) {
        this._a = a;
    }

}