英文:
Why can't you call a method on a null pointer in Java?
问题
在Go语言中,只要不对空指针进行解引用,就可以调用空指针上的方法:
type empty struct{}
func (e *empty) Allocated() bool { return e != nil }
(要运行的代码,请点击这里)
然而,在Java中,即使方法不解引用任何成员变量,调用空指针上的方法仍然会导致空指针异常:
class Test {
public boolean Allocated() { return this != null; }
}
有人知道为什么会出现这种行为吗?它有什么优势吗?有什么想法吗?
英文:
In Go, it is OK to call a method on a null pointer so long as that pointer is never dereferenced:
<!-- language: lang-go -->
type empty struct{}
func (e *empty) Allocated() bool { return e != nil }
(For runnable code, click here)
In Java, however, calling a method on a null pointer, even if the method never dereferences any member variables, still causes a null pointer exception:
<!-- language: lang-java -->
class Test {
public boolean Allocated() { return this != null; }
}
Does anybody know why this behavior exists? Is there some advantage that it gives? Thoughts?
答案1
得分: 12
这是因为所有的Java方法都是虚拟的。
当你写someInstance.Allocated()
时,运行时需要检查someInstance
是否实际上是一个派生类型,该类型重写了这个方法。
理论上,对于final
或private
方法,这个限制可以放宽。
我猜测语言设计者选择不这样做是为了保持一致性。(并且这样移除final
不会造成破坏性变化)
英文:
This is because all Java methods are virtual.
When you write someInstance.Allocated()
, the runtime needs to check whether someInstance
is actually of a derived type that overrides the method.
In theory, this restriction could have been relaxed for final
or private
methods.
I assume that the language designers chose not to for consistency. (and so that removing final
wouldn't be a breaking change)
答案2
得分: 5
_SLaks_的答案从Java的角度来看是很好的。我对Java一无所知,但我了解Go,这是我的答案:
首先,nil
不同于NULL
指针,它们之间有一些根本的区别。
然后,Go中的方法不是类型的实例的一部分,而是类型本身,即Go不像Java那样在对象内部存储vtable:
var e *empty
fmt.Println(e.Allocated())
与以下代码等效(语法糖):
var e *empty
fmt.Println((*empty).Allocated(e)) // 这是有效的代码
注意Allocated
作为*empty
的成员被调用,就像传统的“面向对象”语言中的静态方法一样。
实际上,(*empty).Allocated
只是一个带有奇怪符号的函数名,包括一个点、一个星号和括号。
因为接收器只是另一个参数,它是nil
对于方法分派机制来说是无关紧要的。
> 在Go中,只要指针没有被解引用,就可以在空指针上调用方法
如果你所说的“可以”是合法的意思,那么甚至可以在nil
值上调用方法并对其进行解引用。编译器不会报错,但你会得到一个运行时恐慌。
英文:
The answer by SLaks is good from a Java perspective. I don't have a clue about Java but I know Go and here's my answer:
First of all nil
is not the same as a NULL
pointer, there are some fundamental differences.
Then, methods in Go are not part of a type's instance but the type itself i.e. Go does not store the vtable inside objects, like Java does:
var e *empty
fmt.Println(e.Allocated())
is the same as… (syntactic sugar for…):
var e *empty
fmt.Println((*empty).Allocated(e)) // This is valid code
Note how Allocated
is invoked as a member of *empty
, much like a static method in traditional "OOP" languages.
In fact, (*empty).Allocated
is just a function name with a weird notation that includes a dot, an asterisk and parens.
Because the receiver is just another argument, the fact that it is nil
is unimportant to the method dispatch mechanism.
> In Go, it is OK to call a method on a null pointer so long as that pointer is never dereferenced
If by OK you mean legal, then it's even OK to call a method on a nil
value and dereferencing it. The compiler won't complain - you'll just get a runtime panic.
答案3
得分: -2
我认为这是一个哲学问题;方法(除了静态方法)本质上是应用于对象的,因此在这种范式中,对一个非对象(如“null”)调用这样的方法是没有意义的。如果你想定义一个既可以应用于对象又可以应用于“null”的方法,很容易定义一个静态方法来实现,我认为这样做会使调用该方法的代码对读者来说更加清晰易懂。
英文:
I think it's a philosophical issue; methods (except for static methods) apply to an object, by their very nature, and calling a method like that on a non-object like "null" just doesn't make sense in this paradigm. If you want to define a method that can apply to an object or to "null", it's easy enough to define a static method that does that, and in my opinion that would make the code that calls the method less confusing to readers.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论