There are good reasons to make primitive wrappers final.
First, note that these classes receive special treatment in the language itself - unlike any normal classes, they are recognized by the compiler to implement automatic (un) boxing. Just allowing subclasses would already create pitfalls (expanding a subclass, doing arithmetic, and wrapping would change the type back).
In addition, wrapper types can share instances (for example, see Integer.valueOf (int)), requiring that the wrapper instance be strictly unchanged. Subclass resolution will open a can of worms where immutability can no longer be guaranteed, forcing reliable code to be written as if the wrappers were mutable, leading to protective copies, wasting memory and processor time, and also creating problems with their usefulness in multi-user mode, multi-threaded scripts .
Essence: wrapper types must be unchanged to ensure uniform capabilities in all cases; immunity is an important part of their known properties. And to guarantee immutability, types must be final.
If you need additional functionality, implement it as a utility class, as for primitives (see, for example, java.lang.Math).
Edit: In order to address a case made for “classes are optional”, a final one is needed to ensure immutability. Strictly speaking, it is true that wrappers can be designed as non-final classes, only by making all methods final. This will alleviate most errors, but it will lead to another problem: compatibility with newer versions of Java. Imagine that you decide to create your own subtype MyInteger, which will use the new method, for example. "Integer decrement ()". Everything works fine until ... in Java 20, language developers will not want to add the decment () method to the API (which will be final, as discussed above). Bam, your class is no longer loading, as it is trying to overwrite the final method.