I have not been in a situation where a compiler error caused by these keywords would have saved me from a bug.
It's not so much to save application authors from bugs as to let library authors decide which parts of their implementation they're committing to maintaining.
If I have a library
class C { public void foo() { ... } private void fooHelper() { /* lots of complex code */ } }
I may want to be able to replace foo's implementation and possibly change fooHelper in radical ways. If a bunch of people have decided to use fooHelper despite all the warnings in my documentation then I may not be able to do that.
private lets library authors break libraries into manageable sized methods (and private helper classes) without the fear that they'll be forced to maintain those internal details for years.
What would make it worthwhile for the compiler to enforce information hiding?
On a side note, in Java private is not enforced by the compiler, but by the Java bytecode verifier.
Can reflection override this mechanism? What would make it worthwhile for the compiler to enforce information hiding?
In Java, not only reflection can override this mechanism. There are two kinds of private in Java. The kind of private that prevents one outer class from accessing another outer class's private members which is checked by the bytecode verifier, but also privates that are used by an inner class via a package-private synthetic accessor method as in
public class C { private int i = 42; public class B { public void incr() { ++i; } } }
Since class B (really named C$B) uses i, the compiler creates a synthetic accessor method that allows B to access C.i in a way that gets past the bytecode verifier. Unfortunately, since ClassLoader allows you to create a class from a byte[], it's fairly simple to get at the privates that C has exposed to inner classes by creating a new class in C's package which is possible if C's jar has not been sealed.
Proper private enforcement requires coordination between the classloaders, bytecode verifier, and the security policy which can prevent reflective access to privates.
Can it be used to secure a class' secret state from being attacked?
Yes. "Secure decomposition" is possible when programmers can collaborate while each preserving the security properties of their modules -- I don't have to trust the author of another code module not to violate the security properties of my module.
Object Capabilities languages like Joe-E use information hiding and other means to make secure decomposition possible:
Joe-E is a subset of the Java programming language designed to support secure programming according to object-capability discipline. Joe-E is intended to facilitate construction of secure systems, as well as to facilitate security reviews of systems built in Joe-E.
The paper linked from that page gives an example of how private enforcement makes secure decomposition possible.
Providing secure encapsulation.
Figure 1. An append-only logging facility.
public final class Log { private final StringBuilder content; public Log() { content = new StringBuilder(); } public void write(String s) { content.append(s); } }
Consider Fig. 1, which illustrates how one might build an append-only log facility. Provided that the rest of the program is written in Joe-E, a code reviewer can be confident that log entries can only be added, and cannot be modified or removed. This review is practical because it requires only inspection of the Log class, and does not require review of any other code. Consequently, verifying this property requires only local reasoning about the logging code.