Christopher Riches
Christopher Riches

Reputation: 799

Java - make static nested class visible to all, but only constructed by parent and subclasses of parent

I have a parent class containing a struct-like static nested class. The nested class must be public, as it should be returned to other classes where its contents are acted upon. However, only the parent class and its subclasses should be able to instantiate the nested class, as they know how to define its contents. All classes shown below are in different packages.

public abstract class Parent
{
    public static class Data
    {
        public final String data1
        ...

        public Data(String d1, ...)
        {
            data1 = d1;
            ...
        }
    }

    public abstract Data getData();
}

public final class Subclass extends Parent
{
    @Override
    public Data getData()
    {
        return new Data(.....);
    }
}

public class SomeOtherClass
{
    public void someMethod()
    {
        final Data d = new Subclass().getData();
        System.out.println(d.data1);
    }
}

Declaring the Data class protected would stop getData() from working properly. Decreasing the access modifier on the constructor of Data would prevent subclasses of Parent from working properly. What I want is something like protected-by-parent, which I am guessing does not exist in Java.

Is there a suitable workaround? One possibility I can see is creating a protected method in Parent that effectively mirrors, calls, and returns from the constructor of Data (which would be made private). This however seems a bit messy; does anybody know of a better way/design?

Upvotes: 5

Views: 1036

Answers (2)

Eran
Eran

Reputation: 394146

A better solution would be to make the nested class protected, and make it implement a public interface. Only the interface will be exposed to outside classes, and the nested class itself will remain an implementation detail.

public abstract class Parent
{

    public interface Data {
        public String getData1();
    }

    protected static class DataImpl implements Data
    {
        private final String data1;
        ...

        protected DataImpl(String d1, ...)
        {
            data1 = d1;
            ...
        }
        public String getData1(){
            return data1;
        }
    }

    public abstract Data getData();
}

public final class Subclass extends Parent
{
    @Override
    public Data getData()
    {
        return new DataImpl(.....);
    }
}

public class SomeOtherClass
{
    public void someMethod()
    {
        final Data d = new Subclass().getData();
        System.out.println(d.getData1());
    }
}

Upvotes: 3

Erwin Bolwidt
Erwin Bolwidt

Reputation: 31299

You cannot make a constructor of a static member class protected for the subclasses of the outer class. That expressiveness doesn't directly exist in the Java language.

But, you can make the constructor of the static member class Data private - in that case, the outer class can still access it. And the outer class can define a protected factory method that invokes the Data constructor - by making it protected, it is only accessible to Parent itself, subclasses, and all classes in the same package (as is always the case for the protected modifier)

public abstract class Parent
{
    protected static Data createData(String d1, ...) {
        return new Data(d1, ...);
    }

    public static class Data
    {
        public final String data1
        ...

        private Data(String d1, ...)
        {
            data1 = d1;
            ...
        }
    }

    public abstract Data getData();
}

Upvotes: 3

Related Questions