关闭

从jvm虚拟机聊聊java的方法重载和重写

标签: 重载重写虚拟机jvm
130人阅读 评论(0) 收藏 举报
分类:

首先从定义上说说重载和重写:

  1. 方法重载
    当我们发现在处理同一个功能或者业务的时候,有时候需要不同的参数,我们可以使用方法重载;当我们在修改以前的代码、功能扩展的时候,
    可以使用方法重载。重载特征:同一个类中,两个或者两个以上的方法:
    a、方法名字相同
    b、方法签名不同(签名:方法参数的类型、顺序、个数,三个有一个不同,就代表签名不同)
    c、与方法返回值没有关系
    package com.wb.dispatch;
    
    public class OverLoadTest {
    
    	public OverLoadTest() {
    
    	}
    
    	public void sayHello() {
    		System.out.println("我是无参的!");
    	}
    
    	public void sayHello(String arg) {
    		System.out.println("我是有一个参数的:" + arg);
    	}
    
    	public void sayHello(String arg0, int arg1) {
    		System.out.println("我是有2个参数的:" + arg0 + "和" + arg1);
    	}
    
    	public void sayHello(int arg0, String arg1) {
    		System.out.println("我是有2个参数的:" + arg0 + "和" + arg1);
    
    	}
    }
    

  2. 方法重写
    类a继承类b,当b类中的某一个方法c不能满足类a的需求的时候,需要在类a中对类b的方法c的方法体进行重新实现。
    重写又叫覆写,是以继承为基础的:
    1、子类重写父类(基类)的方法
    2、子类的方法与父类的方法名字、方法签名都要一样
    3、子类的方法与父类的方法返回值也要一样
    4、子类的访问修饰符一样要大于等于父类的访问修饰符(public>protected>default>private)
    5、子类不能抛出新的异常或者比父类声明更宽泛的异常
    4、请增加@Override注解
    public class Animal {
    
        void sayHello(String arg) {
            System.out.println(arg);
        }
    
        protected String sayHello(String arg0, String arg1) {
    
            return arg0 + arg1;
        }
    
        public void sayHello(int arg0){
            System.out.println(arg0);
        }
    }
    public class OverrideTest extends Animal {
        /**
         * 重写了父类方法,修饰符从default扩展到了public
         * @param arg
         */
        @Override
        public void sayHello(String arg) {
            super.sayHello(arg);
        }
    
        /**
         * 重写了父类方法,修饰符从protected扩展到了public
         * @param arg0
         * @param arg1
         * @return
         */
        @Override
        public String sayHello(String arg0, String arg1) {
            return super.sayHello(arg0, arg1);
        }
    
        /**
         * 重写父类方法
         * @param arg0
         */
        @Override
        public void sayHello(int arg0) {
            super.sayHello(arg0);
        }
    }


    
    在了解基本定义是使用后,我们冲jvm层面来聊聊重载和重写1.重载在方法重载时,当需要通过参数类确定调用方法版本的时候,需要看参数的静态类型,而不是实际类型
    java代码首先是通过编译器编译成class的字节码,然后虚拟机加载运行字节码。编译器在编译方法的
    重载时候,是通过参数的静态类型确定方法版本的,静态类型在编译期就确定。
    package com.wb.dispatch;
    
    /**
     * 在方法重载时,当需要通过参数类确定调用方法版本的时候,需要看参数的静态类型,而不是实际类型
     * java代码首先是通过编译器编译成class的字节码,然后虚拟机加载运行字节码。编译器在编译方法的
     * 重载时候,是通过参数的静态类型确定方法版本的,静态类型在编译期就确定。
     * @author wb
     *
     */
    public class AnimalOverLoad {
    
    	static class Animal {
    	}
    
    	static class Dog extends Animal {
    	}
    
    	static class Cat extends Animal {
    	}
    
    	public void sayHello(Animal arg) {
    		System.out.println("hello,animal");
    	}
    
    	public String sayHello(Dog arg) {
    		System.out.println("hello,dog");
    		return "";
    	}
    
    	public Integer sayHello(Cat arg) {
    		System.out.println("hello,cat");
    		return 0;
    	}
    
    	public static void main(String[] args) {
    		Animal animal = new Animal();//静态类型:Animal,实际类型Animal
    		Animal dogAnimal = new Dog();//静态类型:Animal,实际类型Dog
    		Animal catAnimal = new Cat();//静态类型:Animal,实际类型Cat
    
    		Dog dog = new Dog();//静态类型:Dog,实际类型Dog
    		Cat cat = new Cat();//静态类型:Cat,实际类型Cat
    
    		AnimalOverLoad overLoad = new AnimalOverLoad();
    		overLoad.sayHello(animal);// hello,animal
    		overLoad.sayHello(dogAnimal);// hello,animal
    		overLoad.sayHello(catAnimal);// hello,animal
    		overLoad.sayHello(dog);// hello,dog
    		overLoad.sayHello(cat);// hello,cat
    	}
    }


    首先通过javac命令编译AnimalOverLoad,然后使用javap命令查看编译后的字节码javac:
    E:\workspace\JavaVm\src\com\wb\dispatch>javac AnimalOverLoad.java
    Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=GBK
    
    E:\workspace\JavaVm\src\com\wb\dispatch>





    javap:javap -verbose AnimalOverLoad.class
     public static void main(java.lang.String[]);
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=7, args_size=1
             0: new           #9                  // class com/wb/dispatch/AnimalOve
    rLoad$Animal
             3: dup
             4: invokespecial #10                 // Method com/wb/dispatch/AnimalOv
    erLoad$Animal."<init>":()V
             7: astore_1
             8: new           #11                 // class com/wb/dispatch/AnimalOve
    rLoad$Dog
            11: dup
            12: invokespecial #12                 // Method com/wb/dispatch/AnimalOv
    erLoad$Dog."<init>":()V
            15: astore_2
            16: new           #13                 // class com/wb/dispatch/AnimalOve
    rLoad$Cat
            19: dup
            20: invokespecial #14                 // Method com/wb/dispatch/AnimalOv
    erLoad$Cat."<init>":()V
            23: astore_3
            24: new           #11                 // class com/wb/dispatch/AnimalOve
    rLoad$Dog
            27: dup
            28: invokespecial #12                 // Method com/wb/dispatch/AnimalOv
    erLoad$Dog."<init>":()V
            31: astore        4
            33: new           #13                 // class com/wb/dispatch/AnimalOve
    rLoad$Cat
            36: dup
            37: invokespecial #14                 // Method com/wb/dispatch/AnimalOv
    erLoad$Cat."<init>":()V
            40: astore        5
            42: new           #15                 // class com/wb/dispatch/AnimalOve
    rLoad
            45: dup
            46: invokespecial #16                 // Method "<init>":()V
            49: astore        6
            51: aload         6
            53: aload_1
            54: invokevirtual #17                 // Method sayHello:(Lcom/wb/dispat
    ch/AnimalOverLoad$Animal;)V
            57: aload         6
            59: aload_2
            60: invokevirtual #17                 // Method sayHello:(Lcom/wb/dispat
    ch/AnimalOverLoad$Animal;)V
            63: aload         6
            65: aload_3
            66: invokevirtual #17                 // Method sayHello:(Lcom/wb/dispat
    ch/AnimalOverLoad$Animal;)V
            69: aload         6
            71: aload         4
            73: invokevirtual #18                 // Method sayHello:(Lcom/wb/dispat
    ch/AnimalOverLoad$Dog;)Ljava/lang/String;
            76: pop
            77: aload         6
            79: aload         5
            81: invokevirtual #19                 // Method sayHello:(Lcom/wb/dispat
    ch/AnimalOverLoad$Cat;)Ljava/lang/Integer;
            84: pop
            85: return
          LineNumberTable:
            line 36: 0
            line 37: 8
            line 38: 16
            line 40: 24
            line 41: 33
            line 43: 42
            line 44: 51
            line 45: 57
            line 46: 63
            line 47: 69
            line 48: 77
            line 49: 85
    
    
    
    LineNumberTable下有line属性,两个数字说明一下:前面一个是java代码的行号,后面一个字节码行号,这里把java代码行号贴了一下,方便对比:
    

    记住关键点:
    在方法重载时,当需要通过参数类确定调用方法版本的时候,需要看参数的静态类型,而不是实际类型
    java代码首先是通过编译器编译成class的字节码,然后虚拟机加载运行字节码。编译器在编译方法的
    重载时候,是通过参数的静态类型确定方法版本的,静态类型在编译期就确定
    2.重写
    /**
     *方法的重写:
     *1、方法的调用者是根据实际类型动态确定的
     *2、方法版本是根据操作数栈顶元素自下往上找,意思就是优先执行子类方法,子类没有,从父类找,如果都没有找到
     *
     */
    public class Animal {
    
    	static class Cat {
    	}
    	public static class Father {
    
    		public void sayHello(Cat arg) {
    			System.out.println("father is cat");
    		}
    		
    		public void eat(Cat arg) {
    			System.out.println("father eat cat");
    		}
    	}
    
    	public static class Son extends Father {
    		public void sayHello(Cat arg) {
    			System.out.println("son is cat");
    		}
    	}
    	public static void main(String[] args){
    		Father father=new Father();//动态类型father
    		Father son=new Son();//动态类型son
    		father.sayHello(new Cat());//father is cat,动态类型father,直接在Father类中找sayHello方法
    		son.sayHello(new Cat());//son is cat,动态类型是Son,在Son中找sayHello方法
    		father.eat(new Cat());//father eat cat,动态类型是Father,直接在Father类中找eat方法
    		son.eat(new Cat());//father eat cat,动态类型是Son,在Son中找eat方法,没有找到,再从Father中找,
    	}
    
    
    }

    javac编译成class文件:
    E:\workspace\JavaVm\src\com\wb\dispatch>javac Animal.java
    Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=GBK
    
    E:\workspace\JavaVm\src\com\wb\dispatch>


    javap 查看class文件注意关键:方法的重写:
     *1、方法的调用者是根据实际类型动态确定的
     *2、方法版本是根据操作数栈顶元素自下往上找,意思就是优先执行子类方法,子类没有,从父类找,如果都没有找到
    
    
    
    

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:24465次
    • 积分:429
    • 等级:
    • 排名:千里之外
    • 原创:16篇
    • 转载:16篇
    • 译文:0篇
    • 评论:3条
    文章分类
    最新评论