怎么在Java中调用方法(java,开发技术)

时间:2024-05-10 06:11:02 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

一、方法调用

方法调用的唯一目的:确定要调用哪一个方法

方法调用分为解析调用和分派调用

二、非虚方法与虚方法

非虚方法: 静态方法,私有方法,父类中的方法,被final修饰的方法,实例构造器

与之对应不是非虚方法的就是虚方法了

它们都没有重写出其他版本的方法,非常适合在类加载阶段就进行解析(符号引用->直接引用)

三、调用指令

普通调用指令

  • invokestatic:调用静态方法

  • invokespecial:调用私有方法,父类中的方法,实例构造器方法,final方法

  • invokeinterface:调用接口方法

  • invokevirtual: 调用虚方法

使用invokestaticinvokespecial指令的一定是非虚方法

使用invokeinterface指令一定是虚方法(因为接口方法需要具体的实现类去实现)

使用invokevirtual指令的是虚方法

动态调用指令

invokedynamic: 动态解析出需要调用的方法再执行

jdk 7 出现invokedynamic,支持动态语言

测试虚方法代码

父类

publicclassFather{publicstaticvoidstaticMethod(){System.out.println("fatherstaticmethod");}publicfinalvoidfinalMethod(){System.out.println("fatherfinalmethod");}publicFather(){System.out.println("fatherinitmethod");}publicvoidoverrideMethod(){System.out.println("fatheroverridemethod");}}

接口

publicinterfaceTestInterfaceMethod{voidtestInterfaceMethod();}

子类

publicclassSonextendsFather{publicSon(){//invokespecial调用父类init非虚方法super();//invokestatic调用父类静态方法非虚方法staticMethod();//invokespecial调用子类私有方法特殊的非虚方法privateMethod();//invokevirtual调用子类的重写方法虚方法overrideMethod();//invokespecial调用父类方法非虚方法super.overrideMethod();//invokespecial调用父类final方法非虚方法super.finalMethod();//invokedynamic动态生成接口的实现类动态调用TestInterfaceMethodtest=()->{System.out.println("testInterfaceMethod");};//invokeinterface调用接口方法虚方法test.testInterfaceMethod();}@OverridepublicvoidoverrideMethod(){System.out.println("sonoverridemethod");}privatevoidprivateMethod(){System.out.println("sonprivatemethod");}publicstaticvoidmain(String[]args){newSon();}}

怎么在Java中调用方法

注意: 接口中的默认方法也是invokeinterface,接口中的静态方法是invokestatic

四、解析调用

在编译就确定了要调用哪个方法,运行时不可以改变

解析调用 调用的是 非虚方法

五、分派调用

分派又分为静态分派与动态分配

怎么在Java中调用方法

早期绑定:解析调用和静态分派这种编译期间可以确定调用哪个方法

晚期绑定: 动态分派这种编译期无法确定,要到运行时才能确定调用哪个方法

六、静态分派

//静态类型 实际类型 Listlist=newArrayList();

静态分派: 根据静态类型决定方法执行的版本的分派

发生在编译期,特殊的解析调用

典型的表现就是方法的重载

publicclassStaticDispatch{publicvoidtest(Listlist){System.out.println("list");}publicvoidtest(ArrayListarrayList){System.out.println("arrayList");}publicstaticvoidmain(String[]args){ArrayListarrayList=newArrayList();Listlist=newArrayList();StaticDispatchstaticDispatch=newStaticDispatch();staticDispatch.test(list);staticDispatch.test(arrayList);}}/*listarrayList*/

方法的版本并不是唯一的,往往只能确定一个最适合的版本

七、动态分派

动态分派:动态期根据实际类型确定方法执行版本的分派

动态分派与重写有着紧密的联系

publicclassDynamicDispatch{publicstaticvoidmain(String[]args){Fatherfather=newFather();Fatherson=newSon();father.hello();son.hello();}staticclassFather{publicvoidhello(){System.out.println("Fatherhello");}}staticclassSonextendsFather{@Overridepublicvoidhello(){System.out.println("Sonhello");}}}/*FatherhelloSonhello*/

怎么在Java中调用方法

虽然常量池中的符号引用相同,invokevirtual指令最终指向的方法却不一样

分析invokevirtual指令搞懂它是如何确定调用的方法

1.invokevirtual找到栈顶元素的实际类型

2.如果在这个实际类型中找到与常量池中描述符与简单名称相符的方法,并通过访问权限的验证就返回这个方法的引用(未通过权限验证返回IllegalAccessException非法访问异常)

3.如果在实际类型中未找到,就去实际类型的父类中寻找(没找到抛出AbstractMethodError异常)

因此,子类重写父类方法时,根据invokevirtual指令规则,先找实际类型,所以才存在重写的多态

频繁的动态分派会重新查找栈顶元素实际类型,会影响执行效率

为提高性能,JVM在该类方法区建立虚方法表使用索引表来代替查找

字段不存在多态

当子类出现与父类相同的字段,子类会覆盖父类的字段

publicclassDynamicDispatch{publicstaticvoidmain(String[]args){Fatherson=newSon();}staticclassFather{intnum=1;publicFather(){hello();}publicvoidhello(){System.out.println("Fatherhello"+num);}}staticclassSonextendsFather{intnum=2;publicSon(){hello();}@Overridepublicvoidhello(){System.out.println("Sonhello"+num);}}}/*Sonhello0Sonhello2*/

先对父类进行初始化,所以会先执行父类中的构造方法,而构造方法去执行了hello()方法,此时的实际类型是Son于是会去执行Son的hello方法,此时子类还未初始化成员变量,只是有个默认值,所以输出Son hello 0

八、单分派与多分派

publicclassDynamicDispatch{publicstaticvoidmain(String[]args){Fatherson=newSon();Fatherfather=newFather();son.hello(newNod());father.hello(newWave());}staticclassFather{publicvoidhello(Nodnod){System.out.println("Fathernodhello");}publicvoidhello(Wavewave){System.out.println("Fatherwavehello");}}staticclassSonextendsFather{@Overridepublicvoidhello(Nodnod){System.out.println("Sonnodhello");}@Overridepublicvoidhello(Wavewave){System.out.println("Sonwavehello");}}//招手staticclassWave{}//点头staticclassNod{}}/*SonnodhelloFatherwavehello*/

宗量: 方法参数与方法调用者

分派还可以分为单,多分派

单分派:根据一个宗量选择方法

多分派:根据多个宗量选择方法

在编译时,不仅要关心静态类型是Father还是Son,还要关心参数是Nod还是Wave,所以静态分派是多分派(根据两个宗量对方法进行选择)

在执行son.hello(new Nod())时只需要关心实际类型是Son还是Father,所以动态分派是单分派(根据一个宗量对方法进行选择)

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:怎么在Java中调用方法的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:怎么在Html中实现段落空两格下一篇:

5 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18