好吧,我认为可以用一个非常人为的例子来描述它。假设您在 Java 中有一个方法可以打印出 ArrayList 中的所有元素:
void foo(ArrayList list)
{
for(int i = 0; i < list.size(); ++i){
System.out.println(list.get(i).toString());
}
}
现在,如果您像这样调用该方法: someObject.foo(NULL); 当它试图访问列表时,你可能会得到一个 NullPointerException,在这种情况下是调用 list.size(); 现在,您可能永远不会使用这样的 NULL 值调用 someObject.foo(NULL) 。但是,您可能已经从一个返回 NULL 的方法中获取了 ArrayList,如果它在生成 ArrayList 时遇到一些错误,例如 someObject.foo(otherObject.getArrayList());
当然,如果你这样做,你也会遇到问题:
ArrayList list = NULL;
list.size();
现在,在 Objective-C 中,我们有等效的方法:
- (void)foo:(NSArray*)anArray
{
int i;
for(i = 0; i < [anArray count]; ++i){
NSLog(@"%@", [[anArray objectAtIndex:i] stringValue];
}
}
现在,如果我们有以下代码:
[someObject foo:nil];
我们有同样的情况,Java 会产生 NullPointerException。nil 对象将首先在 [anArray count] 处被访问。但是,Objective-C 不会抛出 NullPointerException,而是按照上面的规则简单地返回 0,因此循环不会运行。但是,如果我们将循环设置为运行一定次数,那么我们首先在 [anArray objectAtIndex:i] 处向 anArray 发送消息;这也将返回 0,但是由于 objectAtIndex: 返回一个指针,并且指向 0 的指针是 nil/NULL,因此 NSLog 每次循环都会传递 nil。(虽然 NSLog 是一个函数而不是一个方法,但如果传递一个 nil NSString,它会打印出 (null)。
在某些情况下,最好有一个 NullPointerException,因为您可以立即判断程序有问题,但除非您捕获该异常,否则程序将崩溃。(在 C 中,尝试以这种方式取消引用 NULL 会导致程序崩溃。)在 Objective-C 中,它只会导致可能不正确的运行时行为。但是,如果您有一个在返回 0/nil/NULL/零结构时不会中断的方法,那么这将使您不必检查以确保对象或参数为零。