`
kingj
  • 浏览: 421291 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

java重载

 
阅读更多

     今天看到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的原理。

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics