如果在Java中没有指针的概念,为什么我会遇到一个名为NullPointerException
的异常?
如果在Java中没有指针的概念,为什么我会遇到一个名为NullPointerException
的异常?
Java没有像C语言一样可以轻易操纵并加减任意值的通用指针。对于不习惯使用这种指针的人来说,这可能会导致各种问题。
然而,Java仍然需要区分对象和“无对象”。只是异常的名称表示您正在尝试使用一个没有支持对象的对象引用。
你可以随便给它起名字比如NoObjectException
或者DereferenceException
,或者其他无数的名称,以尽可能地减少人们认为Java具有通用指针的可能性。
但是,NullPointerException
是语言创建者选择的名称,可能是因为他们习惯于在C和/或C++中编码。
是的,这是我学习Java时遇到的第一件让人恼火的事情之一,哈哈。 它真的应该被称为NullReferenceException、NoObjectException或DereferenceException,就像paxdiablo所提到的那样。 引用甚至不必在内部表示为指针,您也不必关心。 “包括Sun在内的大多数虚拟机都使用句柄而不是指针。句柄是指向指针的指针,所以谁知道他们是如何想到使用它的?” 哦,微软的Java虚拟机实际上确实使用指针而不是句柄,所以想象一下。
从技术上讲,这是正确的,它实际上应该被称为NullReferenceException。
因为内部对象变量是指向这些对象的指针。但是,除了在大多数JVM实现上调用System.identityHashCode(object)返回指向对象的指针之外,您无法获得指针值。
编辑:你几乎都是正确的,我几乎是错误的:identityHashCode比仅返回指针要复杂得多。我刚刚看了一下JVM源代码,他们实现了一些哈希代码生成器。然而,在hashCode(一个常数?我不知道)是常数的情况下,它们会返回对象指针。以下是他们的源代码:
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;
}
因为你声明的所有变量(在赋值右侧)都是指向堆空间中某些对象的引用。如果一个引用没有指向任何地方,那么访问该变量会抛出nullpointerexception。