精华内容
下载资源
问答
  • Java多态运行顺序

    2021-04-30 16:04:29
    一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该...

    一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

    两种实现方式:方法的重载(overload)重载指一个类中有多个同名的方法,但这些方法有着不同的参数(个数或者类型),返回类型可以相同也可以不同,因此编译时可以确定到底调用哪个方法,是一种编译时多态。

    方法的覆盖(override,也叫重写)子类可以重写父类的方法,因此同样的方法会在父类和子类中有着不同的表现形式。是运行时多态。一般多态指运行时多态。

    方法重写特点:1.子类重写父类方法2.重写方法的访问修饰符大于等于被重写方法的访问修饰符。3.参数列表相同,返回值一致。4.被重写的方法不能被private5.静态方法不能被重写为非静态方法(编译出错)

    多态三要素:1.要有继承关系2.子类要重写父类的方法3.父类引用指向子类对象(向上转型)

    运行时多态的实现方式为:继承和接口,继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。

    class Animal {  //父类
        String name = "animal";
        static int age = 20;   //静态属性
     
        public void eat() {
            System.out.println("动物 eat");
        }
        protected static void sleep () {  //静态方法
            System.out.println("动物 sleep");
        }
        public void run () {
            System.out.println("动物 run");
        }
    }
     
    class Cat extends Animal {  //子类
        String name = "cat";
        static int age = 12;   //静态属性
     
        @Override
        public void eat() {
            System.out.println("猫 eat");
        }
     
        public static void sleep() {  //父类的静态方法可以被子类继承,但是不能重写。
            System.out.println("猫 run");//这里与父类的方法名相同但是实现不同,所以并未继承!
        }
     
        public void fight() {
            System.out.println("猫 fight");
        }
    }
    
    public static void main(String[] args) {
        Animal animal = new Cat();
     
        System.out.println(animal.name + "  " + animal.age);  //animal  20
        animal.eat();   //猫 eat
        animal.sleep(); //动物 sleep
        animal.run();   //动物 run
    }
    

    根据测试结果,验证了多态的一套规则:

    “成员变量,静态方法看左边;非静态方法:编译看左边,运行看右边。”意思是:当父类变量引用子类对象时(Fu f = new Zi();),在这个引用变量f指向的对象中,他的成员变量和静态方法与父类是一致的,他的非静态方法,在编译时是与父类一致的,运行时却与子类一致(发生了复写)。

    子类Cat中还有一个独有的fight方法,通过animal对象是访问不到的,这时要animal向下转型为Cat,即将父类强制转成子类:

    Cat cat = (Cat) animal;
    cat.fight();
    

    总结:父类引用调用子类对象,编译时看父类引用,运行看子类对象,如果没有重写方法,调用时运行的是父类的方法,
    重写就是为了虽然用的父类的引用,但是调用的却是子类的方法。

    多态的运行顺序this.show(o)->supper.show(o)->this.show(supper(o))->supper.show(supper(o))

    java多态调用优先级_关于java的多态方法调用顺序的问题

    展开全文
  • 根据 Java 多态机制,继承链中对象方法的调用存在一个优先级: this.method(O) -> super.method(O) -> this.method((super)O) -> super.method((super)O) 上面两篇文章中都提到多态机制遵循的规则可以概括为当...
    public class A {
        public String show(D obj) {
            return ("A and D");
        }
    
        public String show(A obj) {
            return ("A and A");
        } 
    }
    
    public class B extends A{
        public String show(B obj){
            return ("B and B");
        }
        
        public String show(A obj){
            return ("B and A");
        } 
    }
    
    public class C extends B{}
    
    public class D extends B{}
    
    public class Test {
        public static void main(String[] args) {
            A a1 = new A();
            A a2 = new B();
            B b = new B();
            C c = new C();
            D d = new D();
            
            System.out.println("(1)"+a1.show(b));  
            System.out.println("(2)"+a1.show(c));  
            System.out.println("(3)"+a1.show(d));   
            System.out.println("(4)"+a2.show(b));   
            System.out.println("(5)"+a2.show(c));   
            System.out.println("(6)"+a2.show(d));   
            System.out.println("(7)"+b.show(b));     
            System.out.println("(8)"+b.show(c));   
            System.out.println("(9)"+b.show(d)); 
    
        }
    }
    

    输出结果:

    (1)A and A
    (2)A and A
    (3)A and D
    (4)B and A
    (5)B and A
    (6)A and D
    (7)B and B
    (8)B and B
    (9)A and D
    

    根据 Java 多态机制,继承链中对象方法的调用存在一个优先级:

    this.method(O) -> super.method(O) -> this.method((super)O) -> super.method((super)O)

    上面两篇文章中都提到多态机制遵循的规则可以概括为当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的。

    以上面的例子举例,A a = new B(); 就是超类对象引用变量 a 引用了子类 B 的对象,最终由 B 来决定调用谁的成员方法,但前提是这个方法即 show 方法必须在超类中定义过的。

    在这里我把这两句话重新排序并解读:

    当超类对象引用变量引用子类对象时,首先这个被调用的方法必须在超类中定义过 = 根据上面继承链对象方法调用优先级可以在超类中找到这个方法
    被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法 = 判断子类是否重写了该方法,如果重写了直接调用子类的方法
    简单来说就是先根据优先级确定目标方法,然后根据多态机制遵循的规则来决定调用子类还是超类的成员方法。

    下面开始分析例子中的九种情况。

    (1)(2)(3) 的例子都不是超类对象引用变量引用子类对象的情况,所以在超类中找到方法后直接调用即可。

    (1) a1.show(b)

    根据优先级第一级 this.method(O) 可改成 A.show(B) ,即要在 A 中 寻找方法 show(B),由于 A 中没有 show(B) 的方法,所以进入第二级 super.method(O) 。
    因为 A 除了 Object 之外没有父类且 Object 中肯定没有 show 方法,所以进入第三级 this.method((super)O) 。
    B 的父类是 A 所以目标是找 A.show(A) ,然后 A 中找到了 show(A) 方法并直接调用,返回 " A and A "。
    (2) a1.show©

    进入第三级 this.method((super)O) 之前跟 (1) 一样。
    C 的父类是 B,并没有在 A 中找到 show(B) 方法,所以会根据 C 的继承链继续向上找 B 的父类 A ,然后寻找 A.show(A) ,所以最终结果跟 (1) 一样是 " A and A "。
    (3) a1.show(d)

    直接根据第一级即可找到目标方法 A.show(D) 并执行得到 " A and D "。
    (4)(5)(6) 都是超类对象引用变量引用子类对象的情况,所以在超类中找到方法后还要根据多态机制规则决定执行子类还是超类的方法。

    (4) a2.show(b)

    根据优先级第一级在 A 中找不到 show(B) ,所以进入第二级。
    因为 A 除了 Object 之外没有父类且 Object 中肯定没有 show 方法,所以进入第三级 。
    根据第三级在 A 中找到了 show(A) ,然后根据多态机制规则由于子类 B 重写了 show(A) 方法,所以最终调用的是 B.show(a) ,得到结果是 " B and A "。
    (5) a2.show©

    进入第三级之前跟 (4) 一样。
    根据第三级在 A 中没有找到 show(B) ,所以会根据 B 的继承链向上找 B 的父类 A ,并在 A 中找到了 show(A) ,然后根据多态机制规则由于子类 B 重写了 show(A) 方法,所以最终调用的是 B.show(a) ,得到结果是 " B and A "。
    (6)a2.show(d)

    直接根据第一级即可找到目标方法 A.show(D) ,然后根据多态机制规则由于子类 B 没有重写 show(A) 方法,所以执行超类方法 A.show(D) ,得到结果为 " A and D "。
    至于(7)(8)(9)根据上面就可以推导出来。

    作者:zYoung_Tang
    链接:https://www.jianshu.com/p/976eec24d9d7
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • Java对上转对象有规定,其特点为: (1)上转对象不能操作子类新增的成员变量;不能使用子类新增的方法。 (2)上转对象可以操作子类继承或隐藏成员变量,也可以使用子类继承的或重写的方法。 (3)如果子类重写了父类...

    先写一个简单的水果之间继承的各个类及关系,方便测试

    class GoldenDelicious extends Apple{
    	public GoldenDelicious(){}
            public void makeAppleCider(){System.out.println("GoldenDelicious");}
    
     }
    
    class Macintosh extends Apple{
          public Macintosh(){}
    }
    
    class Apple extends Fruit{
          public Apple(){}
    }
    
    class Orange extends Fruit{
          public Orange(){}
    }
    
    class Fruit{
          public Fruit(){}
    }


    在main中

    <span style="font-family:SimSun;">Fruit fruit = new GoldenDelicious();
    fruit.makeAppleCider();
    </span>
    刚写完就报错了,提示我们在Fruit中找不到makeAppleCider()方法。这是因为我们用的Fruit fruit = new,相当于这三句
    <span style="font-family:SimSun;">Fruit fruit ;
    GoldenDelicious g = new GoldenDelicious();
    fruit = g;               //g向上转型,fruit称为g的上转型对象</span>

    Java对上转对象有规定,其特点为:

    (1)上转对象不能操作子类新增的成员变量;不能使用子类新增的方法。

    (2)上转对象可以操作子类继承或隐藏成员变量,也可以使用子类继承的或重写的方法。

    (3)如果子类重写了父类的某个方法后,对象的上转型对象调用这个方法时,一定是调用了这个重写的方法。

    (4)可以将对象的上转型对象再强制转化为一个子类对象,这时,该子类对象又具备子类的所有属性和功能。


    对于第一个我们已经证实,子类GoldenDelicious虽然有方法makeAppleCider()方法,但是Fruit类中无该方法,所以访问不到。接下来我们在Fruit类加入方法

    class GoldenDelicious extends Apple{
    	public GoldenDelicious(){}
    	public void makeAppleCider(){System.out.println("GoldenDelicious");}
    
    }
    class Macintosh extends Apple{
    	
    	public Macintosh(){}
    }
    class Apple extends Fruit{
    	public Apple(){}
    	
    }
    class Orange extends Fruit{
    	public Orange(){}
    }
    class Fruit{
    	public Fruit(){}
    	public void makeAppleCider(){System.out.println("fruit");
    }
    	
    }
    main.java:
    Fruit fruit = new GoldenDelicious();
    fruit.makeAppleCider();
    结果:

    GoldenDelicious

    这里可以证实上面的结论②,调用的是GoldenDelicious的方法makeAppleCider();


    其中多态运行顺序为:

      1、当该方法无参数时,那么只看实例化该对象的类是什么,从实例类的开始从下到上找起,一直找到Object类,那一层先有那个无参方法就调用哪一个方法。

      2、当方法有参数时,也是从实例类的开始从下到上找起,不过找的时候会比较参数,看参数的引用是谁,去匹配类方法中参数的类型定位到哪一层的的方法。


    这里对应第一种情况就是先从GoldenDelicious类找起,里面有makeAppleCider(),就用GoldenDelicious的方法makeAppleCider(),不再往上找。

    假如我们去掉GoldenDelicious类方法makeAppleCider(),而在Apple类中加入方法makeAppleCider(),那么按这个顺序,结果应该是apple才对。

    class GoldenDelicious extends Apple{
    	public GoldenDelicious(){}
    	//public void makeAppleCider(){System.out.println("GoldenDelicious");}
    }
    class Macintosh extends Apple{
    	
    	public Macintosh(){}
    }
    class Apple extends Fruit{
    	public Apple(){}
    	public void makeAppleCider(){System.out.println("apple");}
    }
    class Orange extends Fruit{
    	public Orange(){}
    }
    class Fruit{
    	public Fruit(){}
    	public void makeAppleCider(){System.out.println("fruit");}
    	
    }

    结果:apple


    第二种情况解释:

    首先我们在继承类中加入一些带参数的方法,分别在三个类中加入带参方法makeAppleCider(),例如:

    <span style="font-family:SimSun;">class GoldenDelicious extends Apple{
    	public GoldenDelicious(){}
    	public void makeAppleCider(){System.out.println("GoldenDelicious");}
    	public void makeAppleCider(GoldenDelicious obj){System.out.println("GoldenDeliciousTwo");}    //加
    }
    class Macintosh extends Apple{
    	
    	public Macintosh(){}
    }
    class Apple extends Fruit{
    	public Apple(){}
    	public void makeAppleCider(){System.out.println("apple");}
    	public void makeAppleCider(Apple obj){System.out.println("appleTwo");}                        // 加
    }
    class Orange extends Fruit{
    	public Orange(){}
    }
    class Fruit{
    	public Fruit(){}
    	public void makeAppleCider(){System.out.println("fruit");}
    	public void makeAppleCider(Fruit obj){System.out.println("fruitTwo");}                         //加
    	
    }</span>

    现在我们在main()中这样若这样调用:
    Fruit fruit = new GoldenDelicious();
    Fruit fruit1 = new GoldenDelicious();
    fruit.makeAppleCider(fruit1);
    
    结果:

    fruitTwo

    分析:

    这里调用函数时的参数fruit1的引用类型是Fruit,这里先从GoldenDelicious类由下往上找的时候会看里面有没有带有形参类型为Fruit的方法makeAppleCider()

    GoldenDelicious类的makeAppleCider()方法的形参类型为GoldenDelicious,不匹配;所以再向上找到Apple类,里面makeAppleCider()方法的形参类型为Apple,不匹配;

    所以再向上找到Fruit类,里面makeAppleCider()方法的形参类型为Fruit,匹配,所以输出fruitTwo.


    再例如我们将Apple类中的形参类型变一下,变成Fruit,即:

    class GoldenDelicious extends Apple{
    	public GoldenDelicious(){}
    	public void makeAppleCider(){System.out.println("GoldenDelicious");}
    	public void makeAppleCider(GoldenDelicious obj){System.out.println("GoldenDeliciousTwo");}
    }
    class Macintosh extends Apple{
    	
    	public Macintosh(){}
    }
    class Apple extends Fruit{
    	public Apple(){}
    	public void makeAppleCider(){System.out.println("apple");}
    	public void makeAppleCider(Fruit obj){System.out.println("appleTwo");}               //变参数类型
    }
    class Orange extends Fruit{
    	public Orange(){}
    }
    class Fruit{
    	public Fruit(){}
    	public void makeAppleCider(){System.out.println("fruit");}
    	public void makeAppleCider(Fruit obj){System.out.println("fruitTwo");}
    	
    }
    按上面的分析,那么结果应该是 appleTwo

    结果:

    appleTwo


    3.上转型对象的前三个特点我们都已经证实,最后一个可以将对象的上转型对象再强制转化为一个子类对象,这时,该子类对象又具备子类的所有属性和功能

    这样再转化为子类的话,goldendeliciouus又完全具备GoldenDelicious类的所有属性和功能。

    Fruit fruit = new GoldenDelicious();
    GoldenDelicious goldendelicious = (GoldenDelicious)fruit;

    class GoldenDelicious extends Apple{
    	public GoldenDelicious(){}
    	public void makeAppleCider(){System.out.println("GoldenDelicious");}
    }
    class Macintosh extends Apple{
    	
    	public Macintosh(){}
    }
    class Apple extends Fruit{
    	public Apple(){}
    	
    }
    class Orange extends Fruit{
    	public Orange(){}
    	
    }
    class Fruit{
    	public Fruit(){}
    	
    }
    </span>
    结果为:

    GoldenDelicious

    说明:这时的goldendeliciouus对象完全不依赖父类,可以实现GoldenDelicious类的所有属性和功能,包括新增的。


    最后,总结多态的实验过程:

    (1)子类重写父类的方法。

    (2)编译方法时,调用父类定义的方法。

    (3)运行时,根据实际创建的对象类型动态决定使用哪个方法。




    展开全文
  • ,因此在编译时就可以确定到底调用哪个方法,它是一种编译时多态。 2、方法的覆盖:子类可以覆盖父类的方法,因此同样的方法会在父类中与子类中有着不同的表现形式。在java语言中,基类的引用变量不仅可以指向基类...

    java中的多态

        有两种多态的机制:编译时多态、运行时多态

          1、方法的重载:重载是指同一类中有多个同名的方法,但这些方法有着不同的参数。因此在编译时就可以确定到底调用哪个方法,它是一种编译时多态。

          2、方法的覆盖:子类可以覆盖父类的方法,因此同样的方法会在父类中与子类中有着不同的表现形式。在java语言中,基类的引用变量不仅可以指向基类的实例对象,也可以指向子类的实例对象,同样,接口中的引用变量也可以指向其实现类的实例对象。  

    JAVA 运行继承重载的方法先后顺序

          1、程序首先保证的是编译不能出错,所以,方法调用以引用类型为准,引用调用方法的优先级:
      this.show(object) > super.show(object) > this.show(super(object))
     
          2、运行阶段的调用规则是,变量和静态方法优先按引用类型来调用,
     其余方法优先按实例类型来调用!
     

     

    public class A {
        public void show(A a){
            System.out.println("A & A");
        }
    
        public void show(D d){
            System.out.println("A & D");
        }
    }
    /**
     * @program: 
     * @description:
     * @author: Mr.ZY
     * @create: 2019-07-04 22:54
     * B 继续与A 并且重写A的一个show方法 show(A obj)
     **/
    public class B extends A{
        public void show(B obj){
            System.out.println ("B & B");
        }
        //重写父类方法
        public void show(A obj){
            System.out.println ("B & A");
        }
    
    
    }

     

    public class C extends B {
    }
    public class D extends B{
    }

     

    下面是执行代码

    public class TestMain {
    
        public static void main(String [] args){
            /**
             * 程序首先保证的是编译不能出错,所以,方法调用以引用类型为准,引用调用方法的优先级:
             * this.show(object) > super.show(object) > this.show(super(object))
             *
             * 运行阶段的调用规则是,变量和静态方法优先按引用类型来调用,
             * 其余方法优先按实例类型来调用!
             */
    
            A a1 = new A();//实列是A,引用也是A
            A a2 = new B();//实列是B,继承了A ,引用是A
            B b = new B();//实列是B,继承了A,引用是B
            C c = new C();//实列是C,继承了B
            D d = new D();//实列是D,继承了B
            a1.show(b);//a1 b是继承的A, 输出结果为A & A
            a1.show(c);//c是继承的b b又是继承的A, 输出结果为 A & A
            a1.show(d);/** 参照“其余方法优先按实例类型来调用”
                           a1的实列是A,重载方法有第一继承人,所以这里输出的是 A & D
                            */
            a2.show(b);/**实列是B 这里一般会认为调用的是B & B 其实是错误的,
                          因为这里this.show(object) > super.show(object) > this.show(super(object))
                          的顺序,最后调用的this.show(super(object)).所以这里是
                          this.show(A a). 因为B是继承于A  所以显示 B & A
                        */
            a2.show(c); //实列是B, c继承B,B又继承A,原理同上. 所以输出的是 B & A
            a2.show(d); /** 实列是B, A的引用,那么会先查找实列B中是否有 show(D d)的实现
                            当B类中的实现没有,则会从A类中找,刚好A类中有这个方法的实现,
                            所以这里输出的是: A & D
                        */
        }
    }

     

    展开全文
  • 关于java多态方法调用顺序的问题

    千次阅读 2016-03-01 17:29:01
    使用父类类型的引用指向子类的对象,该引用调用的师父类中定义的方法和变量,变量不能被重写(覆盖);如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;  注意特殊情况,...
  • 父类的构造器总是在子类的构造过程中被调用,而且按照继承曾自逐渐向上链接,以使得每个父类的构造器都能得到调用。这样做是有意义的,因为构造器具有一项特殊任务:检查对象是否呗正确的构造。子类只能访问它自己的...
  • Java多态的方法调用顺序问题

    千次阅读 2017-03-06 23:55:12
    这个标题起的有点大,我想说的重点并不是整个的顺序this.method(o)>super.method(o)>this.method((super)o)>super.method((super)o)这个顺序以及多态的详解可以参看一个经典实例理解java的三大特性之多态我在拜读这...
  • Java 多态

    2021-03-31 17:04:53
    Java 多态 多态Java 的一个重要特性,今天我们来聊聊多态. 一. 多态是什么? 多态的字面意思是一个引用拥有多种形态,即多态以继承为基础,根据引用的具体指向不同,使用该引用的操作也会有所不同. 多态更是一种...
  • 子类会有一个默认的无参构造函数,且这个函数中会调用父类的构造函数supe(),来获取父类的所有属性,且这个对父类构造函数的调用会发生在自己的构造函数调用之前 第三第四行,一个是赋予num1的值x,一个是类中的...
  • Java多态

    2019-08-28 01:16:54
    Java多态 多态:(多种形态)是同一个行为具有多个不同表示形式或形态的能力,多态就是同一个接口,使用不同的实例而执行不同的操作. 优点 1.消除类型之间的耦合关系. 2.可替换性 3.可扩充性 4.接口性 5.灵活性 6.简化...
  • 这里是考java多态,**到底调用了哪个函数,**大家直接看下面的代码! public class MyTest { public void hello(Object o) { System.out.println("Object"); } public void hello(String str) { System.out....
  • Java多态基础

    2020-05-01 17:20:46
    Java多态基础 面向对象的三个基本特征:封装,继承,多态。继承和封装比较简单这里就省略了,主要学习一下多态的运用。 多态
  • java 多态

    2020-04-06 23:37:35
    多态的好处和弊端 多态的好处 提高了代码的维护性(继承保证) 提高了代码的扩展性(由多态保证) 多态的弊端 不能使用子类的特有属性和行为。 多态中成员访问的特点 * 多态中的成员访问特点。 * 成员变量:编译看...
  • JAVA 多态

    2019-09-29 14:16:00
    **JAVA多态** 多态实现的必要条件: 1.继承 2.重写 3.向上造型(父类引用派生类对象) 继承: 基本语法: class 类名 extends 父类名 { } 如果没有指定的父类,那么 java 编译器默认 Object 就是该类的父类。 *(1)...
  • Java 多态理解(1)

    2017-05-23 01:55:56
    java,java多态,构造方法的调用顺序
  • java多态

    2017-06-17 17:19:51
    多态 多态通过分离做什么和怎么做,从另一角度将接口和实现分离开来 改善代码的组织结构和可读性,还能创建课扩展的程序—可以写出可以生长的程序 消除类型之间的耦合关系 为所有的导出类提供了一个统一的接口,...
  • 动态绑定:在运行时根据对象的类型调用恰当的方法。Java中除了static方法(构造方法...测试在构造方法中调用该类的多态方法,代码如下。 package polymorphism; class ConstructSuper{ protected int rr = 1; C...
  • 浅谈Java多态

    2020-08-13 15:03:25
    浅谈Java多态 多态 多态是同一个行为具有多个不同表现形式或形态的能力。 多态就是同一个接口,使用不同的实例而执行不同操作。 那么怎么理解这句话呢? 我们假设有基类Animal,两个Animal的派生类Cat和Dog...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,097
精华内容 20,438
关键字:

java多态调用顺序

java 订阅