这篇文章先引出问题,再给出一个例子重现问题。最后通过一些较为官方的资料,来说明引起问题的原因,原理。
在文章开始之前我们先看看一段JDK 8中java.util.Map
的代码。
public interface Map<K,V> {
// ... 省略与本文无关的代码
interface Entry<K,V> {
// ...
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
// ...
}
// ...
我们着重关注一下这段代码:
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
我们知道这句是lambda表达式:
(c1, c2) -> c1.getKey().compareTo(c2.getKey())
那么这句呢?
(Comparator<Map.Entry<K, V>> & Serializable)
我们知道&
是按位与操作
,但是两个数据类型按位与?没见过?
实际上,这是强制类型转换,转换成可序列化的Comparator
。&的意思是且
的意思。
这种强制类型转换可以将一个对象直接转换为Serializable
对象。
我们做个实验来验证一下吧:
public class CollectionTest {
public static String datafile = "C:\\Users\\xxx\\Desktop\\test\\out.out";
interface Function{
void func(String s);
}
public static Function get(){
return (Function & Serializable) ( (s)->System.out.println(s) );
}
public static void main(String[] args) throws IOException {
Function function = get();
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream(datafile)));
out.writeObject(function);
System.out.println("输出完成...");
out.close();
}
}
首先,这是Java语法的支持,是语法的问题,我们现在关注一下语法。
Java语言对强制类型转换表达式(CastExpression)
是按照如下方式定义的:
CastExpression:
( PrimitiveType ) UnaryExpression
( ReferenceType {AdditionalBound} ) UnaryExpressionNotPlusMinus
( ReferenceType {AdditionalBound} ) LambdaExpression
其中AdditionalBound
的定义如下:
AdditionalBound:
& InterfaceType
综上,我们知道强制类型转换表达式(CastExpression)支持lambda表达式,Lambda表达式需要符合如下的语法
:
( ReferenceType & InterfaceType ) LambdaExpression
也就是说Lambda表达式被转化为引用类型和接口类型两种类型
。
其实,引用类型后面可以跟一个或者多个
接口类型,但是所有的类型都需要满足如下条件:
ReferenceType必须要是引用类型或者接口类型
所有的数据类型进行类型消除后
(类型消除是什么?点击查看博文),必须两两不同。
没有两个列出的类型可以是同一通用接口的不同参数化的子类型。
下面我们再给出两个例子结尾:
Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!");
public class Test {
static Object bar(String s) {
return "make serializable";
}
void m () {
SAM s1 = (SAM & Serializable) Test::bar;
SAM s2 = (SAM & Serializable) t -> "make serializable";
}
interface SAM {
Object action(String s);
}
}