好吧,我认为可以用一个非常人为的例子来描述它。假设您在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。将首先在[anArray count]处访问nil对象。但是,按照上面的规则,Objective-C不会返回NullPointerException,而是直接返回0,因此不会运行该循环。但是,如果我们将循环设置为运行一定次数,那么我们首先要通过[anArray objectAtIndex:i]向anArray发送一条消息;这也将返回0,但是由于objectAtIndex:返回一个指针,并且指向0的指针为nil / NULL,因此每次通过循环时,NSLog都将传递nil。(尽管NSLog是一个函数而不是一个方法,但是如果传递了nil NSString,它将输出(空)。
在某些情况下,拥有NullPointerException更好,因为您可以立即告诉程序有问题,但是除非捕获到异常,否则程序将崩溃。(在C语言中,尝试以这种方式取消对NULL的引用会导致程序崩溃。)在Objective-C中,它只会导致可能不正确的运行时行为。但是,如果您有一个方法在返回0 / nil / NULL /归零结构时不会中断,那么您就不必检查以确保对象或参数为nil。