Что такое "тип SAM" в Java?



читая спецификацию Java-8, я продолжаю видеть ссылки на "типы SAM". Я не смог найти четкого объяснения, что это.



Что такое тип SAM и каков пример сценария, когда он может быть использован?

757   1  

1 ответ:

подведем итоги ссылку Джон выложил1 в случае, если он когда-либо пойдет вниз, "SAM" означает "один абстрактный метод", а "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, таким образом, вам не нужно следовать именованию интерфейса методов, и вы можете иметь несколько переопределений сравнения в классе, а затем создать компараторы на лету через лямбда-выражения.

Идем Дальше...

на более глубоком уровне, Java реализует их с помощью invokedynamic байт-код инструкция добавлена в Java 7. Я уже говорил, что объявление лямбда создает экземпляр Callable или Comparable похоже на анонимный класс, но это не строго правда. Вместо этого, в первый раз invokedynamic вызывается, он создает обработчик лямбда-функции с помощью LambdaMetafactory.metafactory метод, затем использует этот кэшированный экземпляр в будущих вызовах лямбды. Более подробную информацию можно найти в ответ.

этот подход является сложным и даже включает в себя код, который может считывать примитивные значения и ссылки непосредственно из стековой памяти для передачи в ваш лямбда-код (например, чтобы обойти необходимость выделения Object[] массив для вызова вашего лямбда), но он позволяет будущим итерациям реализации лямбда заменять старые реализации без приходится беспокоиться о совместимости байт-кода. Если инженеры Oracle изменят базовую реализацию Lambda в более новой версии JVM, lambdas, скомпилированные на более старой JVM, автоматически будут использовать новую реализацию без каких-либо изменений со стороны разработчика.


1 синтаксис ссылки устарел. Взгляните на Лямбда-Выражения Java Trail чтобы увидеть текущий синтаксис.

Comments

    Ничего не найдено.