Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Publicly declare a package private type in a method signature

This is possible in Java:

package x;

public class X {

    // How can this method be public??
    public Y getY() {
        return new Y();
    }
}

class Y {}

So what's a good reason the Java compiler lets me declare the getY() method as public? What's bothering me is: the class Y is package private, but the accessor getY() declares it in its method signature. But outside of the xpackage, I can only assign the method's results to Object:

// OK
Object o = new X().getY();

// Not OK:
Y y = new X().getY();

OK. Now I can somehow try to make up an example where this could somehow be explained with method result covariance. But to make things worse, I can also do this:

package x;

public class X {
    public Y getY(Y result) {
        return result;
    }
}

class Y {}

Now I could never call getY(Y result) from outside of the x package. Why can I do that? Why does the compiler let me declare a method in a way that I cannot call it?

like image 592
Lukas Eder Avatar asked Feb 02 '23 20:02

Lukas Eder


2 Answers

A lot of thinking has gone into the design of Java, but sometimes some sub-optimal design just slips through. The famous Java Puzzlers clearly demonstrate that.

Another package can still call the method with the package-private parameter. The easiest way is to pass it null. But it's not because you can still call it, that such a construct really makes sense. It breaks the basic idea behind package-private: only the package itself should see it. Most people would agree that any code that makes use of this construct is at least confusing and just has a bad smell to it. It would have been better not to allow it.

Just as a side note, the fact that it's allowed opens up some more corner cases. For example, from a different package doing Arrays.asList(new X().getY()) compiles, but throws an IllegalAccessError when executing because it tries to create an array of the inaccessible Y class. That just shows that this leaking of inaccessible types doesn't fit into the assumptions the rest of the language design makes.

But, like other unusual rules in Java, it was allowed in the first versions of Java. Because it's not such a big deal, and because backwards compatibility is more important for Java, improving this situation (disallowing it) simply isn't worth it anymore.

like image 185
Wouter Coekaerts Avatar answered Feb 05 '23 08:02

Wouter Coekaerts


First of all, you could call the method. The trivial example is calling it within the same package.

A non trivial example:

package x;
public class Z extends Y {}

package x2;
    x.getY( new Z() ); // compiles

But that is not the point.

The point is, Java tries to forbid some of the obviously nonsensical designs, but it cannot forbid all.

  1. what is nonsensical? that is very subjective.

  2. if it's too strict, it's bad for development when things are still plastic.

  3. language spec is already way too complicated; adding more rules is beyond human capacity. [1]

[1] http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6

like image 23
irreputable Avatar answered Feb 05 '23 10:02

irreputable