2010-05-07 9 views
12

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

+32

Porque * debería * haberse llamado 'NullReferenceException', pero alguien no estaba pensando correctamente. – skaffman

+2

Esto. Una de mis mascotas Java peeves. – tzaman

+1

@tzaman +1 cuanto más tiempo estudio Java, más me desagrada la incoherencia y la contradicción. –

Respuesta

7

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 paxdiablo. Las referencias ni siquiera tienen que representarse internamente como punteros y no debería tener que preocuparse. "La mayoría de las máquinas virtuales, incluidos los identificadores de uso de Sun, no los punteros. Un identificador es un puntero a un puntero, así que ¿quién sabe cómo se les ocurrió usar eso?" Oh Java VM de Microsoft realmente usa punteros en lugar de identificadores, así que imagínate.

+0

Pero una referencia no es más que un puntero inmutable, al menos conceptualmente, por lo tanto .... – Ingo

10

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.

Podrías llamarlo NoObjectException o DereferenceException, o uno entre 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 los creadores de idiomas eligieron, probablemente porque estaban acostumbrados a codificar en C y/o C++.

+0

Si solo se hubiera incluido nulo en el sistema de tipo: -/ –

+0

@paxidiablo entonces, ¿por qué en la tierra inventaron el final en lugar de usar const. Y si lo piensas final no es tan descriptivo como const. –

+1

Porque const definiría una constante. Final es ligeramente diferente al const de C++ en la medida en que puede retrasar la configuración de la final y, una vez configurado, no se puede cambiar. Me parece que el final es _exactamente_ el término correcto. Una vez que lo configures, bang, ese es el valor final que se le permite tener. – paxdiablo

4

Técnicamente eso es correcto, lo que realmente debería ser llamado NullReferenceException

+1

La referencia es lo mismo que el puntero. Decir que se debe usar un sinónimo, pero no el otro, no tiene sentido. – Val

2

Debido a que internamente las variables de objeto 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.

EDITAR: Estás casi bien, estaba casi equivocado: 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 en que hashCode (una constante? No lo sé) es una constante, devuelven el puntero del objeto. Aquí es 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; 
} 
+0

@Daniel recién salido de curiosidad, ¿y en qué tipo de variable guarda este puntero? –

+0

El puntero en sí es un int. Entonces, en los sistemas de 64 bits, el hash podría ser algo ligeramente diferente (como los 4 bytes superiores xord a los 4 bytes inferiores de la dirección). – Daniel

+2

@Knowing devuelve un int. Pero no es un puntero. Es un ... (espera) ... hashcode. Lo cual en algunas JVMs es una función de la dirección, pero no tiene que ser así. El comportamiento no está especificado por el JLS. Y, por cierto, debido a que es un código hash, dos objetos pueden tener idénticos valores idenityHashCode(). No voy a downvote, pero la última parte de la respuesta de Daniel es incorrecta: es incorrecto en más de un nivel decir que los valores de identityHashCode son punteros. – CPerkins

-1

Si usted tiene un objeto con digamos una lista como un atributo y no asigna explícitamente espacio para ello, el programa que se ejecuta le tirar ese error.

Busque en un depurador (Eclipse o no) para ver qué objetos tienen cuando no los inicializa correctamente y entonces las cosas van a quedar 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.

0

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.

Cuestiones relacionadas