我认为可以用一个非常做作的例子来描述.假设Java中有一个方法,可以打印ArrayList中的所有元素:
void foo(ArrayList list)
{
for(int i = 0; i < list.size(); ++i){
System.out.println(list.get(i).toString());
}
}
现在,如果你这样调用这个方法:someObject.foo(空);当它试图访问列表时,您可能会得到一个NullPointerException,在本例中是在对列表的调用中.大小();现在,你可能永远不会叫某个对象.foo(NULL)与空值类似.但是,您可能是从一个方法中获取ArrayList的,如果该方法在生成ArrayList(如someObject)时遇到错误,它将返回NULL.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/zeroed struct时不会中断,那么就不必判断对象或参数是否为nil.