Reputation: 8102
Why is it possible to return a private
nested class from a public
method in a public
class? Shouldn't the compiler complain about the return type's visibility being less than the method?
public final class Outer {
private static final class Configurator {
private Configurator() {
}
}
public static Configurator configure() {
return new Configurator();
}
}
Upvotes: 6
Views: 1849
Reputation: 76
It's entirely possible and makes sense, although a short practical example is rather difficult. The private class may be returned in place of any of its superclasses. Object has been mentioned here, but it doesn't have to be Object. This example is a little 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();
}
}
Upvotes: 0
Reputation: 298153
There is a strict requirement that interface
methods must be public
. So when the method returning a non-public
type fulfills an interface
contract it must be public
:
class Foo implements Supplier<NonPublicType> {
public NonPublicType get() { // must be public !
…
}
}
Further, it is still possible to call this method from outside the package if the declaring class and the method are public
. But the result has to be assigned to an accessible super type of the non-public
class if it’s going to be used. E.g. if NonPublicType
from the example above implements CharSequence
you could say CharSequence cs=foo.get();
outside the package (if we change Foo
to public
).
Note that the method in question might override a super class method which returns a public
type and return a more specific non-public
type (aka Covariant return type). That method might be called from classes within the same package making use of the more specific type.
Upvotes: 2
Reputation:
A nested class is a member of its enclosing class, so just like in singleton design pattern, when you call the public method to get the private static instance only through that method, it is also possible to call a private static class as a member or one of its methods. The reason you nested it is probably one of the following:
For example if it were private, you can't say:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
So you need a public method to access it in this case.
Upvotes: 0
Reputation: 69339
You can call such a method from outside the class, but only if you are 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 an 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 doesn't break any rules of Java. Object
is simply the only publicly available superclass of your private class.
I doubt there are many practical uses for this pattern. If you wish to return an opaque object, that's better done by passing back a public class with no public methods, since you can at least type-check it when passed back into classes that need to use it.
Upvotes: 4
Reputation: 6570
I think that's because how you're going to deal with the object in the callee can be deferred until the last moment. For example, suppose
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 its toString(), which is inherited 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's Serializable, so I can do something like
public void get() {
Serializable x= MyClass.getX();
}
What I can't do, of course, is to use the type X from outside MyClass, but until I really need it, it's just another instance of Object
Upvotes: -1