You are right. If you create a MyString method and allow inheritance, your program is less safe then if you use the final immutable String class -- this is especially so if you fail to properly document the contract for Overriding methods. If your MyString is mutable, using your class may be even less desirable.
A primary example of an issue with inheritance occurs in the case of self-use of overridable methods. Consider the documentation for java.util.AbstractCollection::remove
:
Removes a single instance of the specified element from this
collection, if it is present (optional operation). More formally,
removes an element e such that (o==null ? e==null : o.equals(e)), if
this collection contains one or more such elements. Returns true if
this collection contained the specified element (or equivalently, if
this collection changed as a result of the call). This implementation
iterates over the collection looking for the specified element. If it
finds the element, it removes the element from the collection using
the iterator's remove method.
The bolded section indicates that the method relies on the iterator method. The AbstractCollection class is designed for inheritance, so the documentation makes it clear that extending classes should consider overriding iterator()
with care. Failing to document this behavior can lead to clients improperly overriding methods, which can lead to undefined behavior. Worse, if you define methods using MyString as an argument, a malicious user could pass in a subclass of MyString to further cause unexpected and potentially harmful changes to your system.
Mutability is desirable because it makes your program simpler to reason about. Critically immutable objects are inherently thread safe and can be shared easily. They also allow Strings to be cached for performance, but you knew about this.
So to answer your question: You can make a mutable, non-final MyString if you wish, but you cannot insure safety. You can only documented inheritance and hope users behave.
Source: My example was blatantly stolen from Joshua Bloch's Effective Java. Specifically item 15 (minimize mutability) and 17 (design and document for inheritance or else prohibit it) are good sources.