在阅读Java-8规范后,我不断看到对“ SAM类型”的引用。我还没有找到关于这是什么的明确解释。
什么是SAM类型?什么时候可以使用的示例场景是什么?
在阅读Java-8规范后,我不断看到对“ SAM类型”的引用。我还没有找到关于这是什么的明确解释。
什么是SAM类型?什么时候可以使用的示例场景是什么?
Answers:
总结乔恩发布的链接1的情况下,它不断下降,“SAM”代表“单一抽象方法”和“SAM型”是指接口等Runnable
,Callable
等Lambda表达式,在Java 8中的新功能,是被视为SAM类型,可以自由转换为它们。
例如,使用这样的接口:
public interface Callable<T> {
public T call();
}
您可以这样声明Callable
使用lambda表达式:
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);
这会创建一个Comparator
使用与共享不同名称的特定方法,Comparator.compare
这样您就不必遵循方法的接口命名,并且您可以在一个类中具有多个比较替代,然后通过即时创建比较器。 lambda表达式。
更深入...
在更深层次上,Java使用invokedynamic
Java 7中添加的字节码指令来实现这些功能。我早些时候曾说过,声明Lambda会创建匿名类Callable
或Comparable
与匿名类相似的实例,但这并非完全正确。相反,第一次invokedynamic
调用时,它将使用LambdaMetafactory.metafactory
方法创建Lambda函数处理程序,然后在以后的Lambda调用中使用此缓存的实例。在此答案中可以找到更多信息。
这种方法很复杂,甚至包括可以直接从堆栈内存中读取原始值和引用以传递到您的Lambda代码中的代码(例如,解决需要分配Object[]
数组来调用Lambda的情况),但是它允许Lambda实现的未来迭代替换旧的实现,而不必担心字节码兼容性。如果Oracle的工程师在较新版本的JVM中更改了基础Lambda实现,则在较旧JVM上编译的Lambdas将自动使用较新的实现,而开发人员无需进行任何更改。
1链接上的语法已过期。查看Lambda Expressions Java Trail,以了解当前语法。