1. ホーム
  2. java

[解決済み] Javaにおける「SAM型」とは何ですか?

2022-04-29 22:21:06

質問

Java-8の仕様書を読んでいると、「SAM型」という言葉をよく目にします。これが何であるかの明確な説明を見つけることができません。

SAM型とはどのようなもので、どのような場面で使われるのか、例を教えてください。

どのように解決するのですか?

要約すると Jonが貼ったリンク 1 SAM型とは、以下のようなインターフェースのことです。 Runnable , Callable などがあります。Java 8の新機能であるラムダ式は、SAM型とみなされ、自由に変換することができます。

例えば、こんなインターフェースで。

public interface Callable<T> {
    public T call();
}

を宣言することができます。 Callable のようなラムダ式を使っています。

Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"

この文脈でのラムダ式は、ほとんどが単なる構文上の糖分である。匿名クラスよりも見栄えが良く、メソッドの命名にも制限がありません。リンク先にあるこの例を見てください。

class Person { 
    private final String name;
    private final int age;

    public static int compareByAge(Person a, Person b) { ... }

    public static int compareByName(Person a, Person b) { ... }
}

Person[] people = ...
Arrays.sort(people, Person::compareByAge);

これは Comparator と同じ名前を持たない特定のメソッドを使用しています。 Comparator.compare そうすれば、メソッドのインターフェイス名に従う必要がなく、1つのクラスで複数の比較オーバーライドを持つことができ、ラムダ式によってその場でコンパレータを作成することができるのです。

もっと深く...

より深いレベルでは、Javaはこれらの実装を invokedynamic というバイトコード命令がJava 7で追加されました。先ほど、Lambdaを宣言すると、Lambdaのインスタンスが生成されると言いました。 Callable または Comparable 匿名クラスと似ていますが、これは 厳密には のようになります。その代わり、最初に invokedynamic が呼び出されると、Lambda 関数ハンドラを作成します。 LambdaMetafactory.metafactory メソッド そして、このキャッシュされたインスタンスを今後のLambdaの呼び出しに使用します。詳しくは この回答 .

このアプローチは複雑で、スタックメモリーからプリミティブ値や参照を直接読み取ってラムダコードに渡すコードも含まれています(例えば、ラムダコードに渡すために Object[] を呼び出すための配列)、バイトコードの互換性を気にすることなく、将来のLambda実装の反復が古い実装を置き換えることを可能にします。Oracle社のエンジニアが新しいバージョンのJVMで基礎となるLambdaの実装を変更した場合、古いJVMでコンパイルされたLambdaは、開発者側で変更することなく自動的に新しい実装を使用することができます。


1 リンク先の構文が古くなっています。リンクの ラムダ式Javaトレイル をクリックすると、現在の構文が表示されます。