JavaインターフェースとObjective-Cプロトコルの違いは?


93

私はJavaを知っており、現在Objective-Cを学んでいます。JavaインターフェースとObjective-Cプロトコルの違いは何ですか?

回答:


82

まず、Javaの作成者の1人による、トピックに関する少し歴史的な視点。次に、ウィキペディアには、Objective-Cプロトコルに関する適度に役立つセクションがあります。特に、Objective-Cは、正式なプロトコル@protocolキーワードで明示的に宣言される、Javaインターフェースに相当)と非公式のプロトコル(リフレクションを介して検出できるクラスによって実装される1つ以上のメソッドのみ)の両方をサポートすることを理解してください。

正式なプロトコル(「インターフェースの実装」を表すObjective-Cの用語)を採用した場合、Javaで期待するように、コンパイラーは実装されていないメソッドに対して警告を発します。 Javaとは異なり(スカッフマンが述べたように)、Objective-Cクラスが正式なプロトコルに含まれるメソッドを実装する場合、そのインターフェースが明示的に採用していなくても、そのプロトコルに「準拠」していると言います。次のように、(- conformsToProtocol:を使用して)コードでプロトコルの適合性をテストできます。

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

注:Appleのドキュメントには次のように記載されています。

「このメソッドは、上に示したように、ヘッダーファイルの正式な宣言のみに基づいて適合性を判断します。プロトコルで宣言されたメソッドが実際に実装されているかどうかを確認するのではなく、プログラマの責任です。」

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は警告ではなくエラーを発行します。
Raffi Khatchadourian、2012年

3
「Objective-Cクラスが正式なプロトコルに含まれるメソッドを実装している場合、そのインターフェースが明示的に採用していなくても、そのプロトコルに「準拠」すると言われます。コードでプロトコルの準拠をテストできます(-conformsToProtocol: )like this "これはFALSEです。-conformsToProtocol:クラスが明示的にプロトコルを採用している場合にのみYESを返します。あなたもそれを試しましたか?
user102008

2
あなたは正しいです。-conformsToProtocol:確かに、クラス(または祖先)がプロトコルを採用することを正式に宣言する必要があります。どうしてこれが間違っているのかわからない、修正してくれてありがとう!
クインテイラー

18

それらはほとんど同じです。ただし、私が気付いたのは、目的のCプロトコルがNSObjectも実装していることを明示的に宣言しない限り、そのプロトコルへの参照はNSObjectが宣言したメソッドにアクセスできない(コンパイラの警告なしで)ことです。javaを使用すると、インターフェースへの参照を保持しながら、toString()などを呼び出すことができます。

例えば

目的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.

目標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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.