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();
}
}
source to share
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.
source to share
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.
source to share
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.
source to share
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();
}
}
source to share
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
source to share