人的记忆力会随着岁月的流逝而衰退,写作可以弥补记忆的不足,将曾经的人生经历和感悟记录下来,也便于保存一份美好的回忆。相信许多人会觉得范文很难写?下面是小编为大家收集的优秀范文,供大家参考借鉴,希望可以帮助到有需要的朋友。
java lambda表达式原理篇一
java 8 开始出现,带来一个全新特性:使用 lambda 表达式 (jsr-335) 进行函数式编程。今天我们要讨论的是 lambda 的其中一部分:虚拟扩展方法,也叫做公共辩护(defender)方法。该特性可以让你在接口定义中提供方法的默认实现。例如你可以为已有的接口(如 list 和 map)声明一个方法定义,这样其他开发者就无需重新实现这些方法,有点像抽象类,但实际却是接口。当然,java 8 理论上还是兼容已有的库。
<
虚拟扩展方法为 java 带来了多重继承的特性,尽管该团队声称与多重继承不同,虚拟扩展方法被限制用于行为继承。或许通过这个特性你可以看到了多重继承的影子。但你还是可以模拟实例状态的继承。我将在接下来的文章详细描述 java 8 中通过 mixin 混入实现状态的继承。
<
什么是混入 mixin?
混入是一种组合的抽象类,主要用于多继承上下文中为一个类添加多个服务,多重继承将多个 mixin 组合成你的类。例如,如果你有一个类表示“马”,你可以实例化这个类来创建一个“马”的实例,然后通过继承像“车库”和“花园”来扩展它,使用 scala 的写法就是:
val myhouse = new house with garage with garden
从 mixin 继承并不是一个特定的规范,这只是用来将各种功能添加到已有类的方法。在 oop 中,有了 mixin,你就有通过它来提升类的可读性。
<
例如在 python 的 socketserver 模块中就有使用 mixin 的方法,在这里,mixin 帮助 4 个基于不同 socket 的 服务,包括支持多进程的 udp 和 tcp 服务以及支持多线程的 udp 和 tcp 服务。
class forkingudpserver(forkingmixin, udpserver): passclass forkingtcpserver(forkingmixin, tcpserver): pass class threadingudpserver(threadingmixin, udpserver): passclass threadingtcpserver(threadingmixin, tcpserver): pass
<
什么是虚拟扩展方法?
java 8 将引入虚拟扩展方法的概念,也叫 public defender method. 让我们姑且把这个概念简化为 vem。
vem 旨在为 java 接口提供默认的方法定义,你可以用它在已有的接口中添加新的方法定义,例如 java 里的集合 api。这样类似 hibernate 这样的第三方库无需重复实现这些集合 api 的所有方法,因为已经提供了一些默认方法。
下面是如何在接口中定义方法的示例:
public interface collection
现在我们来通过 vem 实现一个混入效果,不过事先警告的是:请不要在工作中使用!
下面的实现不是线程安全的,而且还可能存在内存泄露问题,这取决于你在类中定义的 hashcode 和 equals 方法,这也是另外一个缺点,我将在后面讨论这个问题。
<
首先我们定义一个接口(模拟状态bean)并提供方法的默认定义:
public interface switchablemixin { boolean isactivated() default { return vated(this); } void setactivated(boolean activated) default { ivated(this, activated); }}
然后我们定义一个工具类,包含一个 map 实例来保存实例和状态的关联,状态通过工具类中的私有的嵌套类代表:
public final class switchables { private static final map
private static class device {} private static class devicea extends device implements switchablemixin {} private static class deviceb extends device implements switchablemixin {}
<
“完全不同的东西”
上面的实现跑起来似乎挺正常的,但 oracle 的 java 语言架构师 brian goetz 向我提出一个疑问说当前实现是无法工作的(假设线程安全和内存泄露问题已解决)
interface fakebrokenmixin { static map
疑问的解决
第一眼看去,这个实现的代码没有问题。x 是一个只包含一个方法的接口,因为 getname 和 setname 已经有了默认的定义,但 runable 接口的 run 方法没有定义,因此我们可通过 lambda 表达式来生成 x 的实例,然后提供 run 方法的实现,就像 makex 那样。因此,你希望这个程序执行后显示的结果是:
x1x2
如果你删掉 getname 方法的调用,那么执行结果变成:
mytest$1@30ae8764mytest$1@123acf34
这两行显示出 makex 方法的执行来自两个不同的实例,而这时当前 openjdk 8 生成的(这里我使用的是 openjdk 8 24.0-b07).
不管怎样,当前的 openjdk 8 并不能反映最终的 java 8 的行为,为了解决这个问题,你需要使用特殊参数 -xdlambdatomethod 来运行 javac 命令,在使用了这个参数后,运行结果变成:
x2x2
如果不调用 getname 方法,则显示:
mytest$$lambda$1@5506d4eamytest$$lambda$1@5506d4ea
每个调用 makex 方法似乎都是来自相同匿名内部类的一个单例实例,如果观察包含编译后的 java class 文件的目录,会发现并没有一个名为 mytestclass$$lambda$ 的`文件。
<
因为在编译时,lambda 表达式并没有经过完整的翻译,事实上这个翻译过程是在编译和运行时完成的,javac 编译器将 lambda 表达式变成 jvm 新增的指令 invokedynamic (jsr292)。这个指令包含所有必须的关于在运行时执行 lambda 表达式的元信息。包括要调用的方法名、输入输出类型以及一个名为 bootstrap 的方法。bootstrap 方法用于定义接收此方法调用的实例,一旦 jvm 执行了 invokedynamic 指令,jvm 就会在特定的 bootstrap 上调用 lambda 元工厂方法 (lambda metafactory method)。
再回到刚才那个疑问中,lambda 表达式转成了一个私有的静态方法,() -> { n("x"); } 被转到了 mytest:
private static void lambda$0() { n("x");}
如果你用 javap 反编译器并使用 -private 参数就可以看到这个方法,你也可以使用 -c 参数来查看更加完整的转换。
当你运行程序时,jvm 会调用 lambda metafactory method 来尝试阐释 invokedynamic 指令。在我们的例子中,首次调用 makex 时,lambda metafactory method 生成一个 x 的实例并动态链接 run 方法到 lambda$0 方法. x 的实例接下来被存储在内存中,当第二次调用 makex 时就直接从内存中读取这个实例,因此你第二次调用的实例跟第一次是一样的。
<
修复了吗?有解决办法吗?
目前尚无这个问题直接的修复或者是解决办法。尽管 oracle 的 java 8 计划默认激活-xdlambdatomethod 参数,因为这个参数并不是 jvm 规范的一部分,因此不同供应商和 jvm 的实现是不同的。对一个 lambda 表达式而言,你唯一能期望的就是在类中实现你的接口方法。
<
其他的方法
到此为止,尽管我们对 mixin 的模仿并不能兼容 java 8,但还是可能通过多继承和委派为已有的类添加多个服务。这个方法就是 virtual field pattern (虚拟字段模式).
所以来看看我们的 switchable.
interface switchable { boolean isactive(); void setactive(boolean active);}
我们需要一个基于 switchable 的接口,并提供一个附加的抽象方法返回 switchable 的实现。集成的方法包含默认的定义,它们使用 getter 来转换到 switchable 实现的调用:
public interface switchableview extends switchable { switchable getswitchable(); boolean isactive() default { return getswitchable().isactive(); } void setactive(boolean active) default { getswitchable().setactive(active); }}
接下来,我们创建一个完整的 switchable 实现:
public class switchableimpl implements switchable { private boolean active; @override public boolean isactive() { return active; } @override public void setactive(boolean active) { = active; }}
<
这里是我们使用虚拟字段模式的例子:
public class device {} public class devicea extends device implements switchableview { private switchable switchable = new switchableimpl(); @override public switchable getswitchable() { return switchable; }} public class deviceb extends device implements switchableview { private switchable switchable = new switchableimpl(); @override public switchable getswitchable() { return switchable; }}
结论
在这篇文章中,我们使用了两种方法通过 java 8 的虚拟扩展方法为类增加多个服务。第一个方法使用一个 map 来存储实例状态,这个方法很危险,因为不是线程安全而且存在内存泄露问题,这完全依赖于不同的 jvm 对 java 语言的实现。另外一个方法是使用虚拟字段模式,通过一个抽象的 getter 来返回最终的实现实例。第二种方法更加独立而且更加安全。
虚拟扩展方法是 java 的新特性,本文主要介绍的是多重继承的实现,详细你会有更深入的研究以及应用于其他方面,别忘了跟大家分享。
s("content_relate");【详解java中的lambda表达式】相关文章:
1.java中lambda表达式2.java中class对象详解3.java 正则表达式4.java中bigdecimal的操作方法详解5.java的运算符和表达式6.帮助你驾驭java正则表达式7.java中通过final关键字面向对象的详解8.java内存区域的使用详解

一键复制