嗯,我认为可以用一个非常人为的例子来描述它。假设 Java 中有一个方法可以打印 ArrayList 中的所有元素:
void foo(ArrayList list)
{
for(int i = 0; i < list.size(); ++i){
System.out.println(list.get(i).toString());
}
}
现在,如果您像这样调用该方法: someObject.foo(NULL);当它尝试访问列表时,在本例中是在调用 list.size(); 时,您可能会得到一个 NullPointerException 异常。现在,您可能永远不会使用这样的 NULL 值调用 someObject.foo(NULL) 。但是,您可能已经从一个方法获取了 ArrayList,如果在生成 ArrayList 时遇到一些错误(例如 someObject.foo(otherObject.getArrayList()); ),该方法会返回 NULL。
当然,如果你这样做,你也会遇到问题:
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/归零结构时不会中断,那么您就不必检查以确保对象或参数为零。