インターフェースはコントラクトであり、クラスがそのインターフェースを実装する場合、インターフェースからこれらの抽象メソッドを定義する必要があることを理解しています。私が理解していないのは、インターフェイスを使用する2つのクラス間でデータがどのように渡されるかです。
たとえば、Androidでは、Fragmentにインターフェイスがあります(OnFragmentInteractionListenerなど)。それが呼び出すコードのどこかで、
onFragmentInteractionListener.displaySomeMessage(message);
アクティビティは以下を実装します:
void displaySomeMessage(String message) {
System.out.println(message);
}
「メッセージ」は実際にどのようにアクティビティに渡されますか?この特定のデータをどのように取得しますか?私は常にインターフェースを使用しており、その使用方法を知っています。しかし、私は「契約」が実際に舞台裏で何をしているのか全く理解していないので、誰もが同じデータを使用しています。
通常、関数ポインタは、オブジェクトごとに virtual method table のようなデータ構造に格納されます。呼び出されると、最初にテーブルからdisplaySomeMessage
へのポインタを検索し、次に他の関数と同様に呼び出します。引数が関数に渡される方法は、 呼び出し規約 によって異なります。文字列引数を渡すには、通常、ポインタをスタックにプッシュするか、それをレジスタに格納してから、関数ポインタにジャンプします。
Cで GObject for OOPを使用することを学ぶと、仮想メソッドテーブルを理解するのに役立ちます。アセンブリを学ぶと、呼び出し規約を理解するのに役立ちます。
インターフェースは2つのことを行い、どちらも有効なコードの記述に役立ちます。
一方で、インターフェースは、インターフェースを実装するクラス(フラグメントなど)を使用するオブジェクト/クラスへの約束であり、どのクラスでもインターフェースを実装し、メソッドはインターフェースで宣言され、それらはインターフェース。この約束は、コンパイラがそのインターフェイスを呼び出すための正しいコードを生成するのに役立ちます。また、補完機能を提供するIDEを支援するため、自分で名前を覚える必要がありません。
一方、インターフェースを実装するクラスに対しては、特定の引数を持つ特定のメソッドを提供する必要があり、コンパイラーがそのことを確認することに注意してください。それが本質的にインターフェースを「契約」にするものです。
インターフェースが技術レベルでどのように機能するか(コンパイラーが不明なクラスのメソッドを呼び出す方法など)は @ KarlBielefeldtによる回答 で説明されています。