本文将深入了解Lambda表达的实施原则和此类实施计划的交易。
它可以提高代码的简单性和代码的可读性。
例如,在通常的开发过程中,将一个列表转换为另一个列表或地图是一个普遍的要求。这通常是在lambda之前正确的。
重复代码后,每个人都会抽象此通用代码以形成一些库以易于重复使用。上述要求可以抽象:调用列表中的每个元素以转换转换功能转换并输出结果列表。
使用此摘要,可以“简化”初始代码
尽管逻辑较少,但也遗憾的是,代码行的数量已变得更多。由于Java语言中的函数不能以参数为参数,因此该函数只能在类中表示。能够将函数作为参数传递给该方法,我们被迫使用匿名的内部类实现,我们需要添加很多冗余代码。),该函数是首先的公民,可以成为参数传输并作为返回值返回。该代码仅包含没有冗余信息的关键内容。
这种写作效率差距也导致一些Java用户失去了其他语言,但最终最终提供了JDK8中的Lambda表达功能来支持此功能传输。
如果您想以Java语言实现Lambda表达式,则初步观察可以通过Javac将此箭头语法恢复为匿名的内部类,因为它们的功能基本上是等效的(想法中通常会提示)。
但是,匿名内部类有一些缺点。
如果有一个函数参考和指针,则JV.中没有函数类型,而Java中引用了一个对象?反射中有一个方法对象,但其问题是性能问题。每个执行将执行安全检查,并且参数是对象类型,需要拳击等。
还有其他方式指示功能参考吗?这是JDK7中提供指令的新功能。
但是,它将直接实施。由于没有签名信息,因此它将遇到无法重新加载的问题。调用方法性能并不一定要确保其比YATTECODE更好。
JVM上的动态语言(jruby,scala等),实现动态键入动态类型更麻烦。这里是简短的说明什么是动态键入,这与静态键入静态类型相反。静态键入:类型:这些类型在所有变量中,在编译时都可以确定,并且将被检查。DYNAGIC键入:在编译过程中不能确定变量的类型,并且只能在运行时确定和检查。
例如,以下动态语言示例,A和B的类型未知,因此A.Append(B)方法也未知。
编译时可以确定Java中的A型和B类。
编译字节码如下,并且通过变量A的函数签名的方法清楚地调用。
关于该方法调用的字节代码指令,有四种类型的jvmm.invokestatic-称呼静态方法invokeVirtual -palling接口方法IndokeVirtual -calls实例非接口方法的公共方法IndokeSpecial -Othere方法 - 私人,私人,私人,私有方法,构造函数,超级,在编译时清楚地指定了调用指令。哪种方法,您需要在清晰的恒定池中接收对清晰方法的符号引用,并进行类型检查。您不能传递不符合类型类型的对象。相同的方法签名不好。
这种限制使JVM上的动态语言现实主义者感到非常困难,并且只能通过不良的性能反射才能暂时实现。这表明它不能支持字节码级别的动态分布。我应该怎么办?“使用其他间接级别可以解决计算机科学领域的所有建议”。要实现动态分布,因为我们无法在编译过程中决定,因此我们将推迟此决定以运行时和决定,然后用户的自定义代码告诉什么。执行JVM的方法。
在JDK7中,Java提供了解决此问题的说明,与此同时,有一些袋子。大多数用户都不熟悉此说明,因为与Invookestic这样的说明不同,它在其中没有与之相关的直接概念Java语言。
关键概念如下如下
坦率地解决
一开始,在解锁状态下,此指令不知道此时要调用什么目标方法。当JVM首次在某个位置执行指令时,必须先执行该链接。链接进程将通过调用一个来返回一个,当前呼叫相关的信息将返回一个。其中包含的参考是目标。指示正在与此链接,所有呼叫均已在其当前目标上进行调用。对目标是否需要转换,可以分为和平等,并将其划分为可以动态修改以调用通过切换来调用的方法。
让我们看一下当前在Java实施Lambda的方式
以下代码是一个示例
汇编后检查汇编后生成的字节码
与此行相对应的字节代码是
在这里查看步骤。
第一行背后有两个参数。第二个0对0毫无意义,第一个参数为#2。它指向常数池中常数的常数。
该常数对应于#0:#32第二#32表示与此指令相对应的动态方法的名称和方法签名(方法类型)
第一个#0指示bootstrapmethods表中的索引。
查看与JVM虚拟机规范相对应的属性的描述。
此BootstrapMethod属性可以说明指令所需的报价以及参数的数量和类型。
根据JVM规范,BootstrapMethod接收3个标准参数和一些自定义参数。标准参数如下
根据代码解释
已经引入了前三个介绍,其余几个是MethodType sammethodtype:sam(singleabStractMethod),这意味着要实现的方法对象的类型,但没有通用信息(ljava/lang/lang/object;)ljava/ljava/ljava/ljava/;)日志/对象;MethodHandle Inglimethod:要执行的方法的位置。在这里,这是Javac在lambda求解语法后生成后产生的一种方法。后来,MethodType实例化methodtype基本上是相同的,但它将包括通用信息(ljava,(ljava/lang/integer;)ljava/lang/lang/integer;
该方法具有javac求解lambda表达desugar的方法。如果在上下文变量中使用lambda表达式,则是状态。该表达式也称为捕获lambda。该变量将用作此遗传方法参数的参数。当它传递时,没有任何状态不可捕捉。加法,如果您使用java8的methodReference,例如main :: ran,则语法表示该语法表示那里是可以直接调用的方法,无需再生为中间方法。
继续查看此指令,表明当前操作号码堆栈的对象引用了带有索引的本地变量表该类型插入操作号码堆栈中。此处的过程需要继续查看它。
创建一个,然后回电
看看你在做什么:
发生了什么!一个大圆圈之后,我创建了一个内部类!不要先恐慌,完成阅读,最后分析普通内部类之间的区别。
创建过程可能是参数的一些作业和初始化。这是复杂的。方法描述的描述是
创建一个实现功能接口功能的类文件。定义类创建一个没有参数非捕捉类型的类实例,并且可以将呼叫固定返回到此实例。Object.com用普通的InnerClass,有一个内存优化,并且一个对象在没有状态的情况下使用。
实现的第一步是调用SpinnerClass(),通过ASM来生成函数间隔实现,并加载类加载。
生成方法为
这些更为抽象,直观地研究了生成的结果
例如,如果有参数,则从外部类中使用非静态字段,并使用外部局部变量。
相应的结果是
创建内部类后,这是必需的呼叫。如果没有参数,请生成一个内部类函数界面对象示例来创建一个返回此对象的方法handle,然后打包到constantCallsite中。如果有参数,请返回MethodHandle这需要工厂方法的对象实例,以每次生成功能接口并将其包装到ConstantCallsite中。
这完成了Bootstrap的过程。在InvoKedyNakeNicnic链接后,后来的调用直接调用到相应的MethodHandle。特定的实现是返回固定的内部类对象或一次创建新的内部类对象。
让我们考虑一下Java8实现这组表演操作的原因是什么。由于Lambda表达式不需要任何动态分布(哪种方法是清晰的),为什么要使用Invokedy namic?JVM虚拟机的基本保证是低版本类文件也可以在JVM的高版本上运行,JVM虚拟机通过版本升级,该版本正在不断地优化和改善性能。
它只是简单地转换为内部类实现,尽管很简单,但是固定了编译的二进制字节(包括第三党罐装等),并且已修复以创建一个内部类别对象+infin Invoke {虚拟,静态,special,接口} call.essencein未来,只有通过改进创建对象和调用说明才能优化性能的改进。这句话更熟悉的是在这里写入。如果您使用Invokedynamic,在Javac编译足够的信息之后,您可以当JVM执行能够继续优化Lambda表达式并保持兼容性时,动态决定如何实现Lambda,并在将来留下更多。
本文是我对Lambda的一些摘要,其中介绍了lambda表达方式的不同实施思想的原因,实现方法和比较。我刚刚看到了有关Lambda知识的一些代码和信息。如果您有任何错误或不清楚的地方,请无情地指出。