¿Por qué Java tiene una “NullPointerException” cuando no hay punteros en Java?

¿Por qué recibo una excepción llamada NullPointerException si en Java no existe el concepto de puntero?

Sí, esta es una de las primeras cosas molestas que aprendí al aprender Java LOL. Realmente debería llamarse NullReferenceException, NoObjectException o DereferenceException como se menciona en paxdiablo. Las referencias ni siquiera tienen que estar representadas internamente como punteros y no debes tener que preocuparte. “La mayoría de las máquinas virtuales, incluidas las manijas de uso de Sun, no los punteros. Una manija es un puntero a un puntero, ¿quién sabe cómo se las ingenió? Oh Java VM de Microsoft realmente usa punteros en lugar de identificadores, así que imagínate.

No hay punteros de propósito general en Java, que puede manipular fácilmente agregando y restando valores arbitrarios, como en C. Esto puede conducir a todo tipo de problemas para los que no se utilizan para ellos.

Sin embargo, Java aún necesita distinguir entre un objeto y “ningún objeto”. Es solo el nombre de la excepción que significa que está tratando de usar una referencia de objeto que no tiene un objeto de respaldo detrás de ella.

También podría llamarlo NoObjectException o DereferenceException , o uno de una miríada de otros nombres para minimizar la posibilidad de que la gente piense que Java tiene punteros de propósito general.

Pero NullPointerException es lo que optaron los creadores del lenguaje, probablemente porque estaban acostumbrados a codificar en C y / o C ++.

Técnicamente eso es correcto, realmente debería llamarse NullReferenceException

Porque las variables de objetos internos son punteros a esos objetos. Sin embargo, no obtiene el valor del puntero excepto llamando a System.identityHashCode (object) en la mayoría de las implementaciones de JVM, que devuelve el puntero al objeto.

EDIT: Casi está bien, casi me equivoqué: identityHashCode es mucho más complejo que devolver solo un puntero. Solo eché un vistazo a la fuente de JVM e implementaron algunos generadores de código hash. Sin embargo, al menos en el caso donde hashCode (una constante? No sé) es una constante, devuelven el puntero del objeto. Aquí está su fuente para los curiosos:

 static inline intptr_t get_next_hash(Thread * Self, oop obj) { intptr_t value = 0 ; if (hashCode == 0) { // This form uses an unguarded global Park-Miller RNG, // so it's possible for two threads to race and generate the same RNG. // On MP system we'll have lots of RW access to a global, so the // mechanism induces lots of coherency traffic. value = os::random() ; } else if (hashCode == 1) { // This variation has the property of being stable (idempotent) // between STW operations. This can be useful in some of the 1-0 // synchronization schemes. intptr_t addrBits = intptr_t(obj) >> 3 ; value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ; } else if (hashCode == 2) { value = 1 ; // for sensitivity testing } else if (hashCode == 3) { value = ++GVars.hcSequence ; } else if (hashCode == 4) { value = intptr_t(obj) ; } else { // Marsaglia's xor-shift scheme with thread-specific state // This is probably the best overall implementation -- we'll // likely make this the default in future releases. unsigned t = Self->_hashStateX ; t ^= (t << 11) ; Self->_hashStateX = Self->_hashStateY ; Self->_hashStateY = Self->_hashStateZ ; Self->_hashStateZ = Self->_hashStateW ; unsigned v = Self->_hashStateW ; v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ; Self->_hashStateW = v ; value = v ; } value &= markOopDesc::hash_mask; if (value == 0) value = 0xBAD ; assert (value != markOopDesc::no_hash, "invariant") ; TEVENT (hashCode: GENERATE) ; return value; } 

Porque todas las variables (en RHS de asignación) que declara son referencias a algunos objetos en el espacio de montón. Si una referencia no está apuntando a ningún lado, entonces al acceder a esa variable arroja nullpointereception.

Si tiene un objeto con digamos una lista como un atributo y no le asigna espacio explícitamente, el progtwig en ejecución le lanzará ese error.

Mire en un depurador (Eclipse o lo que no) para ver qué contienen sus objetos cuando no los inicializa correctamente y luego las cosas estarán bastante claras.

Creo que se hizo para que haya una noción entre el objeto que tiene espacio en la memoria y el que no.