今天看到think in java的重载部分,大家都知道java的重载是一个方法的方法名称不变,参数类型,参数数量不同(如果这些相同,返回值类型不同,是不同通过javac编译的),但是java重载仅仅只有这些吗?
这里涉及到2个概念:
1、静态分派
2、动态分派
那么,什么是静态分派和动态分派呢?我们来看一个例子(暂时不涉及动态分派的概念),相信大家就都会明白了
package com.zx.exception;
public class Overload {
static class Human{}
static class Man extends Human{}
static class Women extends Human{}
public void hello(Human h){
System.out.println("human");
}
public void hello(Man man){
System.out.println("man");
}
public void hello(Women woman){
System.out.println("woman");
}
public static void main(String[] args) {
Overload l=new Overload();
Human man=new Man();
Human women=new Women();
l.hello(man);
l.hello(women);
System.out.println("=======================");
}
}
我们看到在overload类中有三个重载版本的hello方法,只是参数类型不同,在main方法中我们实例化了Human的两个子类Man以及Woman,执行的结果如下:
human
human
=======================
相信大家都能一眼看出结果,执行结果是两个human,对重载有一定认识的朋友都会知道为什么,这就是我要重点讲解的部分。
java重载是基于静态分派技术实现的,说的通俗一点就是java编译器在编译阶段就会确定方法调用的参数类型,
在main中 声明了这两个对象,Human man=new Man(); Human women=new Women();,对于编译器来说,我们认为它没有那么聪明的知道man是一个Man的实例,women是一个Woman的实例,实际上这些是在运行时才能确定的,所以当你调用l.hell(man) , l.hello(women)的时候,java编译器都会选择
public void hello(Human h){
System.out.println("human");
}
这个hello方法的重载版本,如果你还有疑惑的话,那我们用javap -c com.zx.exception.Overload 来看一下实际编译的字节码是什么:
D:\java\thinkinjava\bin>javap -c com.zx.exception.Overload
Compiled from "Overload.java"
public class com.zx.exception.Overload extends java.lang.Object{
public com.zx.exception.Overload();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public void hello(com.zx.exception.Overload$Human);
Code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String human
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public void hello(com.zx.exception.Overload$Man);
Code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #33; //String man
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public void hello(com.zx.exception.Overload$Women);
Code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #37; //String woman
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public static void main(java.lang.String[]);
Code:
0: new #1; //class com/zx/exception/Overload
3: dup
4: invokespecial #42; //Method "<init>":()V
7: astore_1
8: new #43; //class com/zx/exception/Overload$Man
11: dup
12: invokespecial #45; //Method com/zx/exception/Overload$Man."<init>":()V
15: astore_2
16: new #46; //class com/zx/exception/Overload$Women
19: dup
20: invokespecial #48; //Method com/zx/exception/Overload$Women."<init>":()V
23: astore_3
24: aload_1
25: aload_2
26: invokevirtual #49; //Method hello:(Lcom/zx/exception/Overload$Human;)V
29: aload_1
30: aload_3
31: invokevirtual #49; //Method hello:(Lcom/zx/exception/Overload$Human;)V
34: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
37: ldc #51; //String =======================
39: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return
}
首先来看一下三个hello重载方法的字节码:
hello(Huma)的字节码为:
public void hello(com.zx.exception.Overload$Human);
Code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String human
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
4条指令,getstatic获取System.out的常量池引用,ldc将常量池中索引为0xF6的项"human"加载到当前栈的栈顶,
invokevirtual指令调用System.out的println方法,参数为当前栈顶的值,最后返回。
第二个重载方法
hello(Overload$Man)的字节码为:
public void hello(com.zx.exception.Overload$Man);
Code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #33; //String man
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
方法执行同上
第三个重载方法
hello(Overload$Man)的字节码为:
public void hello(com.zx.exception.Overload$Woman);
Code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #33; //String man
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
方法执行同上
看完了这三个方法后,回到main中去:
public static void main(java.lang.String[]);
Code:
0: new #1; //class com/zx/exception/Overload
3: dup
4: invokespecial #42; //Method "<init>":()V
7: astore_1
8: new #43; //class com/zx/exception/Overload$Man
11: dup
12: invokespecial #45; //Method com/zx/exception/Overload$Man."<init>":()V
15: astore_2
16: new #46; //class com/zx/exception/Overload$Women
19: dup
20: invokespecial #48; //Method com/zx/exception/Overload$Women."<init>":()V
23: astore_3
24: aload_1
25: aload_2
26: invokevirtual #49; //Method hello:(Lcom/zx/exception/Overload$Human;)V
29: aload_1
30: aload_3
31: invokevirtual #49; //Method hello:(Lcom/zx/exception/Overload$Human;)V
34: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
37: ldc #51; //String =======================
39: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return
执行的字节码很简单,就是new 创建三个对象的实例,dup复制这三个实例并推到当前栈顶,astore将实例变量的保存到当前栈的局部变量表中去,关键的地方看26行和31行,我们分别传入了一个Human的实例man和women,然而字节码却是这样的:
26: invokevirtual #49; //Method hello:(Lcom/zx/exception/Overload$Human;)V
31: invokevirtual #49; //Method hello:(Lcom/zx/exception/Overload$Human;)V
这下真相大白于天下了,调用的是Overload类的hello(Human )版本的重载方法
总结:java的重载是基于静态分派实现,也就是说对于某一个类C中方法A的若干个重载版本(A1....AN),C实例的方法A被调用时,java编译器在编译阶段就已经确定了调用者会调用的某一个确定的A版本。这和java的重写Overrite恰恰相反,下一章我会详细讲解Overrite的原理。
分享到:
相关推荐
Java方法重载+Java重载案例+Java重载 Java方法重载+Java重载案例+Java重载 Java方法重载+Java重载案例+Java重载 Java方法重载+Java重载案例+Java重载
java重载
java重载
java重载,重载(Overload):指一个类中可以有多个方法具有相同的名字,但这些方法的参数不同(参数的类型和个数不同),1.重载和返回值类型无关,只和他的三个条件有关,即标红的三个部分。如果两个方法,参数一样...
详解Java 重载
java重载的实现方法
1、本文详细描述了java重载的介绍及使用。 2、通过详细示例,让读者更直观地阅读,更清晰的理解。 3、示例代码可直接复制,编译后可直接运行。 4、根据示例以及运行结果,让读者加强记忆及理解。
java 重载,重写以及继承,多态的区别
java 重载,继承,重写和多态的区别. 下面的例子包含了这四种实现
在Java 中,同一个类中的2个或2...方法重载是Java 实现多态性的一种方式。如果你以前从来没有使用过一种允许方法重载的语言,这个概念最初可能有点奇怪。但是你将看到,方法重载是Java 最激动人心和最有用的特性之一。
重载与重写的区别,详细描述了java中重载与重写的区别。
java 对重载的应用,区别 重载 重写的 区别。让大家认识重载
Java中重载和重写总结,基础知识,概念分清楚,补充基础知识
对Java中方法的重载和重写的具体描述,有利于区分方法的重载和重写
java重载
// 对overload测试的文件:OverloadTest.java public class OverloadTest { // 下面几个方法用来验证可以通过定义不同的参数类型和参数的数目进行方法重载。 public void fun(){ System.out.println("method ...
Java语言中的覆盖重载和多态,方法的多态,类型的多态,多态的优点,覆盖(override)识别标志,方法的重载,构造函数的重载,重载的好处,重载与覆盖的比较,编译时多态和运行时多态
java相关知识的学习笔记,个人整理,里面涵盖:继承,接口,重载,覆盖,final等等的知识点
关于java方法重写的Mypet实例,希望能够为新手学习用