This post is a follow up to the Ultimate Java Puzzler. I was going to name it “The Most Penultimate Java Puzzler Ever to Exist”, but it just doesn’t have the same ring to it anymore :)
The previous post was about the weird relation between default visibility and method overriding, which in the end meant that @Override is broken in some cases. Today we’ll take a look at protected.
The main issue with protected in Java is that unlike C++ and most other OO languages it can pose in one of two incarnations — either as visibility from subtypes or as visibility in the same package (the latter is just like the default visibility). This can sometime lead to some confusion, but I have a specific case of interest to offer you.
In the previous post there already was one example involving protected:
[java]
public class /*p1.*/Main {
public static void main(String[] args) {
C1 c = new p2.C3();
System.out.println(c.m());
}
}
public class /*p1.*/C1 {
/*default*/ int m() {return 1;}
}
public class /*p1.*/C2 extends C1 {
protected int m() {return 2;}
}
public class /*p2.*/C3 extends p1.C2 {
protected int m() {return 3;}
}
[/java]
The relevant part in this example is that protected method is invoked via default visibility, but overridden via subtyping visibility. In case you don’t remember anymore the output is “3″. This shows that visibilities and overriding can be mixed pretty much freely. It is also a good example as it demonstrates why the original phrasing in the JVM spec was wrong. In the original phrasing for the method C3.m to override a method C1.m the latter had to be accessible from the former. In our example this is obviously not the case.
The corrected phrasing, available in the addendum, refers to the JLS notion of overriding, which adds transitivity. That is if C3.m overrides C2.m and C2.m overrides C1.m then C3.m overrides C1.m.
But getting back to the topic — when playing around with JavaRebel I stumbled on an even more interesting example where this dual nature of protected makes it act unexpectedly. The setup starts like this:
[java]
public class /*p1.*/Main {
public static void main(String[] args) {
p2.C2 c = new p2.C2();
System.out.println(c.m());
}
}
public class /*p1.*/C1 {
protected int m() {return 1;}
}
public class /*p2.*/C2 extends p1.C1 {
}
[/java]
This compiles and behaves as expected outputting “1″. A question I’d like to ask is: what happens if for some reason later you override the method m() in C2?
[java]
public class /*p1.*/Main {
public static void main(String[] args) {
p2.C2 c = new p2.C2();
System.out.println(c.m());
}
}
public class /*p1.*/C1 {
protected int m() {return 1;}
}
public class /*p2.*/C2 extends p1.C1 {
protected int m() {return 2;}
}
[/java]
Stop here for a second, take a look at it and hazard a guess…

The example seems similar to the previous one, so you’d expect that the output is “2″. But is it?
Let’s evaluate this from the point of compiler and JVM. Initially the call to C2.m from Main resolved to C1.m(), which is in the same package with Main. When we override the method this is no longer the case and actually the method isn’t accessible anymore. So the correct answer is that the code won’t compile.
This is strongly counterintuitive to me, mainly because I always assumed that overriding a method should never affect its caller in such a way. This also isn’t limited to a compile-time error, as it’s quite possible to compile the C2 without recompiling the rest of the classes and get an IllegalAccessError at runtime. So in my book this reads quite unnatural.
There are definitely more creative ways to f**k up with protected you can come up with, by moving from the “default” incarnation to the subtype one. If you know a good one do post it in the comments.
P.S. I’d love to see what weirdness would come if they’d actually introduce the module keyword as well. Luckily it’d be limited mostly to compile time, but as you saw even there things can get tricky.