【问题标题】:Why does Java have a "NullPointerException" when there are no pointers in Java?当Java中没有指针时,为什么Java会有“NullPointerException”?
【发布时间】:2011-02-16 18:10:32
【问题描述】:

如果在 Java 中没有指针这样的概念,为什么我会得到一个名为 NullPointerException 的异常?

【问题讨论】:

标签: java pointers nullpointerexception


【解决方案1】:

Java 中没有通用指针,您可以像在 C 中那样通过添加和减去任意值来轻松操作这些指针。对于那些不熟悉它们的人来说,这可能会导致各种问题。

但是,Java 仍然需要区分对象和“无对象”。这只是异常的名称,这意味着您正在尝试使用一个没有支持对象的对象引用。

您可以轻松地将其命名为 NoObjectExceptionDereferenceException,或无数其他名称之一,以尽量减少人们认为 Java 具有通用指针的可能性。

但是NullPointerException 是语言创建者选择的,可能是因为他们习惯于使用 C 和/或 C++ 进行编码。

【讨论】:

  • 如果类型系统中只包含 null :-/
  • @paxidiablo 那么为什么他们发明了 final 而不是使用 const。如果你仔细想想 final 并没有 const 那样具有描述性。
  • 因为 const 会定义一个常量。 Final 与 C++ 中的 const 略有不同,因为您可以延迟设置 final,一旦设置,就无法更改。在我看来,final 完全是正确的术语。设置好之后,砰,这就是它允许拥有的最终值。
  • Java 是面向对象的(至少有人告诉过我)。那么为什么需要区分对象和“无对象”呢?在面向对象的系统中,“空指针/引用”等同于 NullObject 或 UndefinedObject。该对象很可能无法理解发送给它的大部分消息并以这种方式触发错误,但不需要“NullPointerException”。真正的原因是答案的最后一句话。 “实际上,我创造了“面向对象”这个术语,我可以告诉你,我并没有想到 C++。 (艾伦·凯)
【解决方案2】:

是的,这是我在学习 Java LOL 时学到的第一件令人讨厌的事情。 正如 paxdiablo 所提到的,它确实应该被称为 NullReferenceException、NoObjectException 或 DereferenceException。 引用甚至不必在内部表示为指针,您不必关心。 “包括 Sun 的大多数 VM 都使用句柄​​,而不是指针。句柄是指向指针的指针,所以谁知道他们是如何使用它的?” 哦,微软的 Java VM 实际上确实使用指针而不是句柄,所以去看看吧。

【讨论】:

  • 但是引用只不过是一个不可变的指针,至少在概念上是这样,因此......
【解决方案3】:

技术上没错,确实应该叫 NullReferenceException

【讨论】:

  • 引用同指针。说必须使用一个同义词而不使用另一个同义词是无稽之谈。
【解决方案4】:

因为内部对象变量是指向这些对象的指针。但是,除了在大多数 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;
}

【讨论】:

  • @Daniel 只是出于好奇,您将这个指针存储在什么变量类型中?
  • 指针本身是一个int。因此,在 64 位系统上,哈希值可能略有不同(例如地址的 4 个高位字节与 4 个低位字节的异或)。
  • @Knowing 它返回一个 int。但它不是指针。这是一个......(等待它)......哈希码。在某些 JVM 中,它是地址的函数,但并非必须如此。 JLS 未指定该行为。顺便说一下,因为它是一个哈希码,所以两个对象可以有相同的 identityHashCode() 值。我不会投反对票,但丹尼尔回答的最后一部分是不正确的:说 identityHashCode 值是指针在不止一个层面上是错误的。
  • @Daniel,引用在内部不能是指针,因为指针和引用是一回事。它们是同义词。
  • @Val:在某些系统上,引用是在元数据中标识的指针,因此如果 GC 冻结程序的执行并检查调用堆栈,它可以确定每个未固定指针/引用的位置对象位于。当程序被冻结时,GC 可以将一个对象复制到一个新位置,并将每个指向它的指针替换为指向新副本的指针;一些聪明的算法可以使这变得非常便宜。一个“普通”指针只能存在于一个对象,如果它是固定的; GC 无法判断所有普通指针的位置,但它不需要。
【解决方案5】:

因为您声明的所有变量(在赋值的 RHS 上)都是对堆空间中某些对象的引用。如果引用未指向任何位置,则在访问该变量时会引发 nullpointerexception。

【讨论】:

    【解决方案6】:

    如果你有一个对象,比如说一个列表作为属性,并且你没有明确地为它分配空间,正在运行的程序会抛出这个错误。

    查看调试器(Eclipse 或其他),看看当你没有正确初始化对象时,你的对象会保存什么,然后事情就会很清楚了。

    我认为这样做是为了在内存中有空间的对象和没有空间的对象之间存在一个概念。

    【讨论】:

      猜你喜欢
      • 2013-09-07
      • 2022-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-10
      • 2012-02-02
      • 1970-01-01
      相关资源
      最近更新 更多