丹丹学妹哭着对我说:学长,Java零基础入门百度云

本文探讨了Java中的动态类型语言特性,重点在于MethodHandle的概念和作用。MethodHandle作为Java虚拟机的一项增强,允许在运行时动态确定方法调用,模拟了类似函数指针的效果,提升了动态语言在JVM上的灵活性。同时,文章对比了静态类型与动态类型、强类型与弱类型的差异,并介绍了运行时异常和连接时异常的区别。
摘要由CSDN通过智能技术生成

sda

sdad【注】:

sdad①、什么叫类型检查呢? 就是一个对象引用对应的实例类型必须是静态类型的子类,而有的语言就不需要比如:JavaScript。只要对象引用对应的实例类型中的方法定义中确实包含有要执行的方法,能够找到相同签名的方法,调用便可成功。

sdad②、产生这种差异的根本原因(对于①): 是Java语言在编译期间却已将要执行的方法完整的符号引用生成出来,并作为方法调用指令的参数(操作数)存储到Class文件中。 而这个符号引用包含了该方法定义在哪个具体类型之中、方法的名字以及参数顺序、参数类型和方法返回值等信息,通过这个符号引用,Java虚拟机就可以翻译出该方法的直接引用。 (而JavaScript等动态类型语言与Java有一个核心的差异就是对象引用本身并没有类型,他的值才具有类型,所以编译器在编译时最多只能确定方法名称、参数、返回值这些信息,而不会去确定方法所在的具体类型(即方法接收者不固定)。“变量(对象引用)无类型而变量值才有类型”这个特点也是动态类型语言的一个核心特征。)

sda

静态类型语言与动态类型语言的比较?

sda

sdad①、静态类型语言能够在编译期确定变量类型,最显著的好处是编译器可以提供全面严谨的类型检查,这样与数据类型相关的潜在问题就能在编码时被及时发现,利于稳定性及让项目容易达到更大的规模。

sdad②、动态类型语言在运行期才确定类型,这可以为开发人员提供极大的灵活性。

sda

什么叫动态语言呢?

sda

sdad 运行期间,允许改变程序结构(例如引进新函数、删除旧函数)或变量类型。比如Python.

sda

什么叫强类型语言呢?什么叫弱类型语言?

sda

sdad强类型语言是一种强制类型定义的语言,一旦某一个变量被定义类型,如果不经过强制转换,则它永远就是该数据类型了,强类型语言包括Java、.net 、Python、C++等语言。

sda

sdad弱类型语言是一种弱类型定义的语言,某一个变量被定义类型,该变量可以根据环境变化自动进行转换,不需要经过显性强制转换。弱类型语言包括vb 、PHP、javascript等语言。

sda

sdad无论是强类型语言还是弱类型语言,判别的根本是是否会隐性的进行语言类型转变。强类型语言在速度上略逊于弱类型语言,但是强类型定义语言带来的严谨性又能避免不必要的错误。

sda

什么叫运行时异常?什么叫连接时异常?

sasdasdsad

sdad运行时异常: 只要代码不执行到这一行就不会出现问题;

sdad连接时异常: 即使导致连接时异常的代码放在一条根本无法被执行到的路径分支上,类加载时也照样会抛出异常。

sasdasdsad

sasdasdsadsadsadsadasdasdasdasdsadsadsaasddad异常代码示例


public static void main(String[] args) {

	int[][][] array = new int[1][0][-1];

} 

sdad分析:

sdad①、Java中是能正常编译的,但运行会出现NegativeArraySizeException异常,《Java虚拟机规范》中规定是一个运行时异常

sdad②、C中直接在编译期报错。

sdad总结:一门语言的哪一种检查行为要在运行期进行,哪一种检查要在编译期进行并没有什么必然的因果逻辑关系。


Java与动态类型

===========================================================================

背景介绍:

sdad 目前已经有许多动态类型语言运行于Java虚拟机之上了,如Clojure、Groovy、Jython和JRuby等,也就是说我们可以在JVM上实现静态类语言的严谨与动态类型语言的灵活。

sd ad但是JDK7以前,JVM层面对动态类型语言的支持一直都还有所欠缺,主要表现在方法调用方面,只有4条方法调用指令(invokevirtual、invokespecial、invokestatic、invokeinterface),且它们的第一个参数(操作数)都是被调用的方法的符号引用(CONSTANT_Methodref_info或者CONSTANT_InterfaceMethodref_info常量)。

sda

sdad这时就有一个问题:方法的符号引用在编译时产生,而动态类型语言只有在运行期才能确定方法的接收者。

sda

sdad那怎么解决这个问题的呢?

sda

sdad ①、曲线救国:比如编译时留个占位符类型,运行时动态生成字节码实现具体类型到占位符类型的适配。但是这样有两个缺点:

sdaadⅠ、让动态类型语言实现的复杂度增加,也会带来额外的性能和内存开销sdadⅡ、由于无法确定调用对象的静态类型,而导致的方法内联无法有效进行。

sda

sdaad基于以上背景,在JVM层面上提供动态类型的直接支持就成为Java平台发展必须解决的问题,直到JDK 7,JSR-292提出了invokedynamic指令以及java.lang.invoke包解决了此问题。


java.lang.invoke包


sdad这个包的主要目的:在之前单纯依靠符号引用来确定调用的目标方法这条路之外,提供一种新的动态确定目标方法的机制,称为“方法句柄”(Method Handle)。

sda

sdad**[注]:** 在Java语言中做不到像C那样,单独把一个函数作为参数(函数指针的功劳)进行传递。普遍的做法是设计一个带有compare()方法的Comparator接口,以实现这个接口的对象作为参数。比如void sort(List list, Comparator c)

sda

sdad不过在有了方法句柄之后,Java语言就可以像C那样,拥有类似于函数指针或者委托的方法别名这样的工具了。

sasdasdsad

sasdasdsadsadsadsadasdasdasdasdsadsadsaasddad方法句柄演示


import static java.lang.invoke.MethodHandles.lookup;

import java.lang.invoke.MethodHandle;

import java.lang.invoke.MethodType;



public class MethodHandleTest {

	static class ClassA {

		public void println(String s) {

			System.out.println(s);

		}

	}

	public static void main(String[] args) throws Throwable {

		Object obj = System.currentTimeMillis() % 2 == 0 ? System.out : new ClassA();

		// 无论obj最终是哪个实现类,下面这句都能正确调用到println方法。

		getPrintlnMH(obj).invokeExact("icyfenix");

	}

	private static MethodHandle getPrintlnMH(Object reveiver) throws Throwable {

		// MethodType:代表“方法类型”,包含了方法的返回值(methodType()的第一个参数)

		//和具体参数(methodType()第二个及以后的参数)。

		MethodType mt = MethodType.methodType(void.class, String.class);  //pritln的返回值、以及具体参数

		

		/*lookup()方法来自于MethodHandles.lookup,这句的作用是在指定类中查找(符合给定的方法名称、

		方法类型,并且符合调用权限的)方法句柄。

		因为这里调用的是一个虚方法,按照Java语言的规则,方法第一个参数是隐式的,代表该方法的接收者,

		也即this指向的对象,这个参数以前是放在参数列表中进行传递,现在提供了bindTo()方法来完成这件事情。

		*/ 

		return lookup().findVirtual(reveiver.getClass(), "println",mt).bindTo(reveiver);//方法类型、名称、即返回值和参数

	}

} 

方法解析:

sdad方法getPrintlnMH()中实际上是模拟了invokevirtual指令的执行过程,只不过它的分派逻辑并非固化在Class文件的字节码上,而是通过一个由用户设计的Java方法来实现。而这个方法本身的返回值(MethodHandle对象),可以视为对最终调用方法的一个“引用”。

sdad我们再次回顾sort()方法,有了MethodHandle就可以写出类似于C/C++那样的函数声明了:

sdasdasdasdasdsadasdsadasdasdasdasadvoid sort(List list, MethodHandle compare)

到此,我们发现MethodHandle在使用方法和效果上与Reflection有众多相似之处。但是它们也有 很大的区别:

sasad①、ReflectionMethodHandle机制本质上都是在模拟方法调用。但是Reflection是在模拟Java代码层次的方法调用,而MethodHandle是在模拟字节码层次的方法调用。在MethodHandles.Lookup上的3个方法findStatic()、findVirtual()、findSpecial()正是为了对应于invokestatic、invokevirtual(以及invokeinterface)和invokespecial这几条字节码指令的执行权限校验行为,而这些底层细节在使用Reflection API时是不需要关心的。

sasad②、Reflection中的java.lang.reflect.Method对象远比MethodHandle机制中的java.lang.invoke.MethodHandle对象所包含的信息来得多。

ssadasdasad前者是方法在Java端的全面映像,包含了方法的签名、描述符以及方法属性表中各种属性的Java端表示方式,还包含执行权限等的运行期信息。

ssadasdasad后者仅包含执行该方法的相关信息。

sasad③、Reflection API的设计目标是只为Java语言服务的,而MethodHandle则设计为可服务于所有Java虚拟机之上的语言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值