什么是Java中的“SAM类型”?

时间:2013-07-28 22:06:53

标签: java lambda java-8

阅读Java-8规范,我不断看到对“SAM类型”的引用。我无法找到明确解释这是什么。

什么是SAM类型?什么是何时可以使用?

2 个答案:

答案 0 :(得分:111)

总结the link Jon posted 1 以防它出现故障,“SAM”代表“单一抽象方法”,“SAM类型”指代{{1}这样的接口Lambda表达式是Java 8中的一个新特性,被认为是SAM类型,可以自由转换为它们。

例如,使用如下界面:

Runnable

您可以使用如下的lambda表达式声明Callable

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

此上下文中的Lambda表达式大多只是语法糖。它们在代码中看起来比匿名类看起来更好,并且对方法命名的限制更少。从链接中获取此示例:

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); ,这样您就不必遵循方法的界面命名,并且可以进行多次比较在类中重写,然后通过lambda表达式动态创建比较器。

更深入......

在更深层次上,Java使用Java 7中添加的Comparator字节码指令实现这些。我之前说过,声明Lambda会创建一个Comparator.compareinvokedynamic的实例,类似于匿名类,但这不是严格真。相反,第一次调用Callable时,它会使用LambdaMetafactory.metafactory method创建一个Lambda函数处理程序,然后在将来调用Lambda时使用此缓存实例。更多信息可以在this answer找到。

这种方法很复杂,甚至包括可以直接从堆栈内存读取原始值和引用以传递到Lambda代码的代码(例如,需要分配Comparable数组来调用Lambda),但是它允许Lambda实现的未来迭代替换旧的实现,而不必担心字节码兼容性。如果Oracle的工程师在较新版本的JVM中更改了基础Lambda实现,则在较旧的JVM上编译的Lambdas将自动使用较新的实现,而不会对开发人员进行任何更改。


1 链接上的语法已过期。请查看Lambda Expressions Java Trail以查看当前语法。

答案 1 :(得分:1)

具有一种抽象方法的接口,称为单一抽象方法接口(SAM接口)。

通常,它们被称为功能接口。

  • 只需要一种抽象方法
  • @FunctionalInterface注释可以添加
  • 默认方法不是抽象的,因此我们可以添加任意数量的默认方法
  • 允许将Object类的方法重写为抽象的
  • 功能性(SAM)接口对于编写lambda非常重要 表情
  • 在Java 8中的java.util.function包下添加了许多功能(SAM)接口

您可以在What is SAM interface?

阅读更多内容