There are good reasons to makes the primitive wrappers final.
First, note that these classes get special treatment in the language itself - unlike any normal classes, these are recognized by the compiler to implement auto(un)boxing. Simply allowing subclasses would already create pitfalls (unwrapping a subclass, performing arithmetic and wrapping back would change the type).
Also, wrapper types can have shared instances (e.g. look at Integer.valueOf(int)) requiring that an instance of a wrapper is strictly immutable. Allowing subclasses would open up a can of worms where immutability can no longer be assured, forcing robust code to be written as if the wrappers were mutable, leading to defensive copies, wasting memory and CPU time and also creating issues with their usefulness in multi-threaded scenarios.
Essence: wrapper types need to be immutable to ensure uniform capabilities across all instances; immutablility being an important part of their known properties. And to guarantee immutability, the types need to be final.
If you need added functionality, implement it as utility class like you would do for primitives (see java.lang.Math for example).
Edit: To address the case made for "the classes needn't" be necessary final to ensure immutability. Strictly speaking this is true, the wrappers could be designed as non-final classes, only making all of the methods final. That would alleviate most of the pitfalls, but it leads to another issue: compatibility with new java versions. Imagine you decided to create your own subtype MyInteger sporting a new method, e.g. "Integer decrement()". Everything works fine, until... in Java 20 the language designers decide to add a decrement() method to the API (which would be final as discussed above). Bam, your class no longer loads, since it attempts to overwrite a final method.
Answer from Durandal on Stack OverflowThere are good reasons to makes the primitive wrappers final.
First, note that these classes get special treatment in the language itself - unlike any normal classes, these are recognized by the compiler to implement auto(un)boxing. Simply allowing subclasses would already create pitfalls (unwrapping a subclass, performing arithmetic and wrapping back would change the type).
Also, wrapper types can have shared instances (e.g. look at Integer.valueOf(int)) requiring that an instance of a wrapper is strictly immutable. Allowing subclasses would open up a can of worms where immutability can no longer be assured, forcing robust code to be written as if the wrappers were mutable, leading to defensive copies, wasting memory and CPU time and also creating issues with their usefulness in multi-threaded scenarios.
Essence: wrapper types need to be immutable to ensure uniform capabilities across all instances; immutablility being an important part of their known properties. And to guarantee immutability, the types need to be final.
If you need added functionality, implement it as utility class like you would do for primitives (see java.lang.Math for example).
Edit: To address the case made for "the classes needn't" be necessary final to ensure immutability. Strictly speaking this is true, the wrappers could be designed as non-final classes, only making all of the methods final. That would alleviate most of the pitfalls, but it leads to another issue: compatibility with new java versions. Imagine you decided to create your own subtype MyInteger sporting a new method, e.g. "Integer decrement()". Everything works fine, until... in Java 20 the language designers decide to add a decrement() method to the API (which would be final as discussed above). Bam, your class no longer loads, since it attempts to overwrite a final method.
This is a security feature that lets libraries use strings and wrappers for primitives in collections or otherwise without making "defensive copies".
If users were allowed to derive their own values, say, from Integer, they could make a mutable version of it. Then they could pass instances of this Integer to a library that expects a collection of Integers, like this:
class ApiClass {
private final List<Integer> intList;
ApiClass (List<Integer> ints) {
// Make a defensive copy
intList = new ArrayList<Integer>(ints);
// Go through the list, and check the values
...
}
}
Currently the constructor should make a defensive copy of the collection, but a shallow copy is sufficient, because Integers inside cannot change. If Java did not insist on Integer being final, however, there would be no such guarantee, so the code would have to make a deep copy. Otherwise the caller could construct ApiClass by passing valid Integers in a list, and then go through that list of MyIntegers, and change their values to what the constructor would consider invalid. This would break assumptions of other methods inside ApiClass, potentially causing crashes or exposing information that the "plain" Integer would not leak.
They are final for security reasons. There may be other reasons, but security is the most important.
Imagine an ability to inherit java.lang.String, and supply your own, mutable implementation to a security-sensitive API. The API would have no choice but take your string (remember the substitution principle) then but you would be able to change the string from under them (on a concurrent thread or after the API has returned), even after they have checked it to be valid.
Same goes for wrappers of primitives: you do not want to see them mutable under any circumstance, because it would violate important assumptions about their behavior encoded in the APIs using these classes.
Making String final addresses this issue by not letting others supply their own, potentially hostile, implementations of classes as fundamental as String.
You might want to prevent other programmers from creating subclasses or from overriding certain methods. For these situations, you use the final keyword.
The String class is meant to be immutable - string objects can't be modified by any of their methods. Since java does not enforce this, the class designers did. Nobody can create subclasses of String.
Hope this answers your question.