String and StringBuffer (and new friend CharSequence which you should really look at too) are a great big poke in the eye to one of the very tenets of object-oriented programming. In order to understand how to best use them and why.... you have to look at the source code, thus violating encapsulation. Tsk.
Actually (starting a war here
) I think the poke should go in the eye of OO programming. OO tends to gloss over the fact that to write efficient code you sometimes, perhaps often, NEED to know the basics of the implementation.
E.g. you have the java.utils.Collection interface.. but you have to choose an implementation to actually create a collection. E.g. Maybe you want a Set, if you *require* it to be Sorted you would be better off to use the SortedSet interface from the get go... then you've narrowed it enough that there is only one implementationin the JRK to choose - TreeSet.
BUT, lets say you don't care about order or anything. Do you use a HashSet, an ArrayList, or a TreeSet or .... You need to know how you will be using it and then you have to pick an implementation that suits how you will use it... If you will be calling the 'contains(obj)' method frequently a List will suck.. a TreeSet will be better, and a HashSet better yet. Without knowning the implementation it is difficult or impossible to optimize without guessing.
What if you need an ordered list.. you pick the List interface of course, but should it be ArrayList or LinkedList... The classes in the JDK are named specifically to advertise the implementation and the JavaDocs go further to confirm the implementation... it's done that way because you NEED to know.
Note that I'm not bashing OO techniques, I'm just pointing out that there are some obvious times when knowledge of the implementation is required to write efficient code. Understanding the implementation of String and StringBuffer is one of those things you need to know.