Java接口与Objective-C协议的区别?

94

我懂Java,现在正在学习Objective-C。Java接口和Objective-C协议之间的区别是什么?

2个回答

83

首先,由Java的创造者之一提供了一些关于此主题的历史背景。接下来,维基百科上有一个关于Objective-C协议的章节,对理解Objective-C支持的正式协议(使用@protocol关键字显式声明,相当于Java接口)和非正式协议(只是由类实现的一个或多个方法,并可以通过反射发现)很有帮助。

如果您采用正式协议(Objective-C术语中的“实现接口”),编译器将像在Java中一样发出有关未实现方法的警告。如果Objective-C类实现了正式协议中包含的方法,则称其符合该协议,即使其接口没有明确采用该协议(这一点与Java不同,正如skaffman所提到的那样)。您可以在代码中测试协议符合情况(使用-conformsToProtocol:),例如:

if ([myObject conformsToProtocol:@protocol(MyProtocol)]) {
    ...
}

注意:苹果公司的文档指出:

"此方法仅基于头文件中的正式声明进行判断是否符合协议。它不会检查协议中声明的方法是否实际被实现,这是程序员的责任。"

自Objective-C 2.0(在OS X 10.5“Leopard”和iOS中)起,正式协议现在可以定义可选方法,只要类实现了所有必需的方法,就可以遵循协议。您可以使用@required(默认)和@optional关键字来切换后续方法声明必须可以被实现以符合协议。(请参阅Apple的Objective-C 2.0编程语言指南中讨论可选协议方法的部分。)

可选协议方法为开发人员提供了很多灵活性,特别是用于实现代理监听器。您可以采用协议并仅实现您关心的可选方法,而不是扩展诸如MouseInputAdapter之类的东西(这可能很烦人,因为Java也是单继承),或者实现许多无意义的空方法。使用此模式,调用者在调用它之前检查该方法是否被实现(使用-respondsToSelector):

if ([myObject respondsToSelector:@selector(fillArray:withObject:)]) {
    [myObject fillArray:anArray withObject:foo];
    ...
}

如果反射的开销成为问题,您可以随时缓存布尔结果以便重用,但要抵制过早优化的冲动。 :-)


4
如果你采用正式协议(Objective-C 对于“实现接口”的术语),编译器会像在Java中一样,对未实现的方法发出警告。在这种情况下,Java会发出错误提示,而不是警告。 - khatchad
3
如果一个Objective-C类实现了一个正式协议中包含的方法,即使其接口没有明确采用该协议,也可以说它“符合”该协议。您可以在代码中测试协议符合性(使用-conformsToProtocol:),如下所示。这是错误的。-conformsToProtocol:只有在类明确采用协议时才会返回YES。你试过吗? - user102008
2
你是正确的,-conformsToProtocol:确实要求类(或祖先)正式声明采用协议。不确定我怎么会错了,感谢您的纠正! - Quinn Taylor

18
它们几乎是相同的。然而,唯一让我困惑的是,除非你明确声明一个Objective-C协议也实现了NSObject,否则对该协议的引用将无法访问NSObject声明的方法(即使编译器会发出警告)。而在Java中,您可以拥有对接口的引用,并且仍然可以调用它的toString()等方法。
例如:
Objective-C:
@protocol MyProtocol
// Protocol definition
@end

id <MyProtocol> myProtocol;

 [myProtocol retain] // Compiler warning

Java:

public interface MyInterface {
// interface definition
}

MyInterface myInterface;

myInterface.toString();  // Works fine.

Objective C (fixed):


目标C(已修复):
@protocol MyProtocol <NSObject>
// Protocol definition
@end

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning

25
这是因为id和NSObject 不是同一个东西。在Java中,根对象是Object。在Objective-C中,NSObject是一个根对象,但不是对象。如果你想访问所有NSObject方法(包括类方法和协议),请明确指出:NSObject<MyProtocol> myProtocol; 而不是:id<MyProtocol>... 当你使用id时,你是在说:我不关心这个对象,只关心*协议,而在你的情况下这并不是真的。 - Jason Coco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接