How does a public method return a private type?

Why is it possible to return a private

nested class from a method public

to a class public

? Should the compiler complain less about the visibility of the return type than the method?

public final class Outer {
    private static final class Configurator {
        private Configurator() {
        }
    }

    public static Configurator configure() {
        return new Configurator();
    }
}

      

+3


source to share


5 answers


You can call such a method from outside the class, but only if you're happy to throw away the result.

public class TestClass {
  public static void main(String[] args) throws Exception {
    Outer.configure(); // this is valid
  }
}

      

or if you are happy to refer to the result as Object

:



public class TestClass {
  public static void main(String[] args) throws Exception {
    Object o = Outer.configure(); // this is valid
  }
}

      

The compiler allows this because it does not violate any Java rules. Object

is just the public superclass of your private class.

I doubt there are many practical uses for this pattern. If you want to return an opaque object, it is best to do so by passing in a public class with no public methods, as you can at least check the type when it comes back to the classes that need to use it.

+3


source


There is a strict requirement for methods to interface

be public

. So when a method that returns a type doesn't public

fulfill the contract interface

, it should be public

:

class Foo implements Supplier<NonPublicType> {
  public NonPublicType get() { // must be public !
  }
}

      




In addition, you can still call this method from outside the package if the declaration class and method public

. But the result must be assigned to the available supertype of the class non public

if it is to be used. For example. if NonPublicType

from the above example implements CharSequence

, you can tell CharSequence cs=foo.get();

outside of the package (if we change Foo

to public

).

Note that this method can override a superclass method that returns a type public

and returns a more specific type public

(aka Covariant return type ). This method can be called from classes within the same package using a more specific type.

+2


source


A nested class is a member of its enclosing class, so just like in the singleton design pattern, when you call a public method to get a private static instance only through that method, you can also call the private static class as a member or one of its methods. The reason you invested it is probably one of the following:

  • Logically grouping classes that are only used in one place
  • To increase encapsulation
  • To get more readable and maintainable code

For example, if it was private, you cannot say:

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass();

      

So you need a public accessor for it in this case.

0


source


This is perfectly possible and makes sense, although the short practical example is rather difficult. A private class can be returned in place of any of its superclasses. An Object is mentioned here, but it doesn't have to be an Object. This example is a bit on the wacky side, but it works.

abstract class Super {
    abstract void zipper();
}

final class Outer {

    private static final class Configurator extends Super {
        private Configurator() {
        }

        @Override
        void zipper() {
            System.out.println("Zip!");
        }
        public void zoomer() {
            System.out.println("Zoom!");
        }

    }

    public static Configurator configure() {
        return new Configurator();
    }

}

public final class PublicPrivate {

    public static void main(final String[] args) {
        /* Outer.configure returns an instance of Configurator, 
            a subclass of Super */
        final Super = Outer.configure();
        /* Configurator.zoomer() is not available, 
            because Configurator is private */
        // o.zoomer(); /* Uncomment this line and the compile will fail */
        /* But Super.zipper() is available,
            in the form in which Configurator overrid it */
        o.zipper();
    }

}

      

0


source


I think that since you are going to be dealing with an object in the callee can be deferred until the last moment. For example, suppose that

private static class X{

}

public static MyClass.X getX() {
    return new MyClass.X();
}

      

then from another class i do something like

public void get() {
    System.out.println(MyClass.getX());
}

      

I don't need to know what type X is here because println just wants it toString (), which inherits from Object.

Another example

private static class X implements Serializable{

}

public static MyClass.X getX() {
    return new MyClass.X();
}

      

In this case, I don't know X, but I know it is Serializable, so I can do something like

public void get() {
    Serializable x= MyClass.getX();
}

      

What I can't do, of course, is to use type X from outside of MyClass, but until I need it, it's just another instance of Object

-1


source







All Articles