Java中的“SAM类型”是什么?
阅读Java-8规范,我不断看到对“SAM类型”的引用。我无法找到关于这是什么的明确解释。
什么是 SAM 类型,何时可以使用 SAM 类型的示例方案是什么?
阅读Java-8规范,我不断看到对“SAM类型”的引用。我无法找到关于这是什么的明确解释。
什么是 SAM 类型,何时可以使用 SAM 类型的示例方案是什么?
为了总结Jon发布的链接1以防万一它出现故障,“SAM”代表“单个抽象方法”,“SAM类型”指的是,等接口。Lambda 表达式是 Java 8 中的一项新功能,它被视为 SAM 类型,可以自由转换为它们。RunnableCallable
例如,使用如下界面:
public interface Callable<T> {
public T call();
}
您可以像这样声明一个 using lambda 表达式:Callable
Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"
在此上下文中,Lambda 表达式大多只是语法糖。它们在代码中比匿名类看起来更好,并且对方法命名的限制更少。从链接中举个例子:
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 表达式动态创建比较器。ComparatorComparator.compare
更深入...
在更深层次上,Java使用Java 7中添加的字节码指令来实现这些。我之前说过,声明 Lambda 会创建一个匿名类的实例或类似于匿名类,但这并不是严格意义上的。相反,在第一次调用 时,它会使用 LambdaMetafactory.metafactory 方法创建一个 Lambda 函数处理程序,然后在将来调用 Lambda 时使用此缓存的实例。更多信息可以在这个答案中找到。invokedynamicCallableComparableinvokedynamic
这种方法很复杂,甚至包括可以直接从堆栈内存中读取基元值和引用的代码,以传递到您的 Lambda 代码中(例如,绕过需要分配数组来调用 Lambda 的代码),但它允许 Lambda 实现的未来迭代来替换旧的实现,而不必担心字节码兼容性。如果 Oracle 的工程师在较新版本的 JVM 中更改了底层 Lambda 实现,则在较旧的 JVM 上编译的 Lambda 将自动使用较新的实现,而无需开发人员进行任何更改。Object[]
1 链接上的语法已过期。查看 Lambda 表达式 Java Trail 以查看当前语法。