`
kingj
  • 浏览: 427753 次
  • 性别: 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的原理。

 

 

 

分享到:
评论

相关推荐

    java重载介绍及使用

    在Java编程语言中,方法的重载(Overloading)是一个重要的概念,它允许我们在同一个类中定义多个同名方法,但这些方法的实现必须有所不同。主要的不同之处在于它们的参数列表,包括参数的数量、类型或者顺序。这种...

    java重载的实现方法

    Java重载的实现方法详解 Java重载(Overload)是Java编程语言中的一种机制,它允许在同一个类中定义多个方法,具有相同的名称,但参数列表不同。这种机制可以提高代码的灵活性和可读性。本文将详细介绍Java重载的...

    Java重载.docx

    Java中的方法重载是面向对象编程的一个重要特性,它允许我们在同一个类中定义多个具有相同名称但参数列表不同的方法。这样做不仅提高了代码的可读性,还使得代码更易于维护和扩展。以下是对方法重载的详细解释: 1....

    Java重载构造原理与用法详解

    Java重载构造原理与用法详解 Java重载构造原理与用法详解是Java编程语言中的一种重要概念,它涉及到方法重载、构造器、可变参数、递归算法、封装等多个方面的知识点。下面将对这些知识点进行详细的解释和分析。 一...

    java重载代码分享.zip

    下面将详细解释Java重载的概念、规则以及在实际编程中的应用。 1. **概念理解**: - 重载(Overloading)是多态性的一种表现,即在同一个作用域内,一个类可以有多个同名的方法,它们之间的区别在于传入的参数列表...

    Java方法重载+Java重载案例

    Java方法重载+Java重载案例+Java重载 Java方法重载+Java重载案例+Java重载 Java方法重载+Java重载案例+Java重载 Java方法重载+Java重载案例+Java重载

Global site tag (gtag.js) - Google Analytics