This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
Well... you can define a method in Derived which looks as though it would override the method in PrivateOverride; but it won't be a polymorphic method. If you do something like this inside the class PrivateOverride:
PrivateOverride po = new Derived(); po.f();
you'll see it print "private f()", so your "override" really isn't an override.
But that wasn't really what you were asking. You were asking why the last class won't compile, right? The compiler decides the accessibility ("public-ness") of a method based on the compile-time type of the variable you're calling the method with. In other words, the fact that Derived has a public method called f() isn't even considered; all the compiler knows is that the variable is of type "PrivateOverride," and this class has no accessible method of that name.
You can only call Derived.f() through a variable of type "Derived".
So, now you're wondering why it matters that you can make a method "more public" if you can't then call the method? Honestly, it's not really useful that often. One case where it's used is to make Object.clone() public in a Cloneable object. You override the method to be public, and call super.clone() to invoke the Object version. Not very elegant, but as I said, this feature isn't really all that useful.