7

在 Go 中,只要该指针永远不会被取消引用,就可以在空指针上调用方法:

type empty struct{}
func (e *empty) Allocated() bool { return e != nil }

(对于可运行的代码,请单击此处

然而,在 Java 中,在空指针上调用方法,即使该方法从未取消引用任何成员变量,仍然会导致空指针异常:

class Test {
    public boolean Allocated() { return this != null; }
}

有谁知道为什么存在这种行为?它有什么好处吗?想法?

4

3 回答 3

12

这是因为所有 Java 方法都是虚拟的。

编写someInstance.Allocated()时,运行时需要检查是否someInstance实际上是覆盖该方法的派生类型。

final从理论上讲,对于或private方法可以放宽此限制。
我假设语言设计者选择不这样做是为了保持一致性。(因此删除final不会是一个重大变化)

于 2013-07-09T19:46:41.460 回答
5

从 Java 的角度来看, SLaks的答案很好。我对Java一无所知,但我知道Go,这是我的答案:

首先指针nil不一样NULL,有一些根本区别

然后,Go 中的方法不是类型实例的一部分,而是类型本身,即 Go 不会像 Java 那样将 vtable 存储在对象中:

var e *empty
fmt.Println(e.Allocated())

与...相同(...的语法糖):

var e *empty
fmt.Println((*empty).Allocated(e)) // This is valid code

请注意如何Allocated作为 的成员调用*empty,很像传统“OOP”语言中的静态方法。

实际上,(*empty).Allocated它只是一个带有点、星号和括号的奇怪符号的函数名称。

因为接收者只是另一个参数,所以它对nil方法分派机制并不重要。

在 Go 中,可以在空指针上调用方法,只要该指针永远不会被取消引用

如果 OK 你的意思是合法的,那么在一个nil值上调用一个方法并取消引用它甚至是可以的。编译器不会抱怨——你只会遇到运行时恐慌。

于 2013-07-10T08:29:00.480 回答
-2

我认为这是一个哲学问题。方法(静态方法除外)就其本质而言适用于对象,并且在像“null”这样的非对象上调用类似的方法在此范例中没有意义。如果你想定义一个可以应用于对象或“null”的方法,那么定义一个静态方法就很容易了,而且在我看来,这将使调用该方法的代码不那么容易让读者感到困惑。

于 2013-07-09T19:59:15.130 回答