Todo proviene del hardware.
Un byte es la unidad de memoria direccionable más pequeña en la mayoría del hardware.
Cada tipo que acaba de mencionar está construido a partir de un múltiplo de bytes.
Un byte es de 8 bits. Con eso puedes expresar 8 booleanos pero no puedes buscar solo uno a la vez. Se dirige a 1, se dirige a los 8.
Y solía ser así de simple, pero luego pasamos de un bus de 8 bits a un bus de 16, 32 y ahora de 64 bits.
Lo que significa que si bien aún podemos direccionar en el nivel de bytes, ya no podemos recuperar un solo byte de la memoria sin obtener sus bytes vecinos.
Frente a este hardware, los diseñadores de idiomas eligieron permitirnos elegir tipos que nos permitieran elegir tipos que se ajustaran al hardware.
Puede afirmar que ese detalle puede y debe abstraerse, especialmente en un lenguaje que apunta a ejecutarse en cualquier hardware. Esto tendría problemas de rendimiento ocultos, pero puede que tenga razón. Simplemente no sucedió de esa manera.
Java realmente intenta hacer esto. Los bytes se promueven automáticamente a Ints. Un hecho que te volverá loco la primera vez que intentes hacer un trabajo de cambio de bits serio en él.
Entonces, ¿por qué no funcionó bien?
El gran argumento de venta de Java en el pasado es que podrías sentarte con un algoritmo C bien conocido, escribirlo en Java y con pequeños ajustes funcionaría. Y C está muy cerca del hardware.
Mantener ese tamaño y abstraer el tamaño de los tipos integrales simplemente no funcionó en conjunto.
Entonces podrían haberlo hecho. Simplemente no lo hicieron.
Quizás el programador no quiera que alguien pueda usar un número mayor que cierto tamaño y esto les permite limitarlo.
Este es un pensamiento válido. Hay métodos para hacer esto. La función de sujeción para uno. Un lenguaje podría llegar a romper límites arbitrarios en sus tipos. Y cuando esos límites se conocen en tiempo de compilación, eso permitiría optimizaciones en cómo se almacenan esos números.
Java simplemente no es ese lenguaje.