XJL's Blog

保持乐观、单纯。 要开心。

爱家人朋友,爱猫咪,爱学习。


相信大家对于Java 的多态已经有一些了解了,那么我问以下问题:

Java面向对象的三大特性是什么?

你会毫不犹豫的答出:

继承、封装、多态!

好的,不错,那接下来咱们继续:

多态的三个条件是什么呢?

嗨,背面试题谁不会呢?

  • 要有继承
  • 要有重写
  • 父类引用指向子类对象

回答的不错,很自信!那么下面这段代码执行的结果是什么呢:

public class TeachPolymorphic {

    public static void main(String[] args) {
        TeachPolymorphic teachPolymorphic = new TeachPolymorphic();
        Coder coder = teachPolymorphic.new JavaCoder();
        coder.occupation();
    }

    public class Coder{
        public void occupation() {
            System.out.println("我的职业是一名程序员");
        }

        public void codeType() {
            System.out.println("我写代码");
        }
    }

    public class JavaCoder extends Coder {

        public void occupation() {
            System.out.printf("我是一名Java 程序员");
        }

        public void codeType() {
            System.out.printf("我写Java 代码");
        }
    }
}

你终于来点实战的了,当然是:

我是一名Java 程序员

不错不错,越来越自信了,JavaCoder的occupation()重写了Coder中的方法,调用时确实应该是执行JavaCoder中的的occupation()方法。那我们来点更干货的内容咯:

public class StudyPolymorphic {
    public static void main(String[] args) {
        StudyPolymorphic studyPolymorphic = new StudyPolymorphic();
        Coder coder1 = studyPolymorphic.new Coder();
        Coder coder2 = studyPolymorphic.new JavaCoder();
        JavaCoder javacoder = studyPolymorphic.new JavaCoder();
        KotlinCoder kotlinCoder = studyPolymorphic.new KotlinCoder();
        coder1.workWithMate(javacoder);
        coder1.workWithMate(kotlinCoder);
        coder2.workWithMate(javacoder);
        coder2.workWithMate(kotlinCoder);
    }

    public class Coder{
        public void workWithMate(Coder mate){
            System.out.println("程序员和程序员");
        }

        public void workWithMate(KotlinCoder mate){
            System.out.println("程序员和Kotlin程序员");
        }
    }

    public class JavaCoder extends Coder{
        public void workMate(JavaCoder mate) {
            System.out.println("Java程序员和Java程序员");
        }

        @Override
        public void workWithMate(Coder mate) {
            System.out.println("Java程序员和程序员");
        }
    }

    public class KotlinCoder extends JavaCoder{
        public void workMate(KotlinCoder mate) {
            System.out.println("Kotlin程序员和Kotlin程序员");
        }

        @Override
        public void workMate(JavaCoder mate) {
            System.out.println("Kotlin程序员和Java程序员");
        }
    }
}

额, 有挑战了,应该是:

程序员和程序员 程序员和Kotlin程序员 Java程序员和Java程序员 程序员和Kotlin程序员

不好意思你答错了,应该是:

程序员和程序员 程序员和Kotlin程序员 Java程序员和程序员 程序员和Kotlin程序员

咦!为什么呀?

别急,我先说Java多态的这一点:

当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量 的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中 定义过的,也就是说被子类覆盖的方法。 (但是如果强制把超类转换成子 类的话,就可以调用子类中新添加而超类没有的方法了)

其他几个对了,说明你理解了,那我解释一下第三个吧:

当运行coder2.workWithMate(javacoder)时,由于coder2是一个Coder对象,javacoder是一个JavaCoder对象,而JCoder中没有对应的withMate(JavaCoder mate)方法,那么这时候就会调用withMate(Coder mate)方法,但调用时发现该方法已经被JavaCoder重写了,所以这时候就会转而调用JavaCoder 的withMate(Coder mate)方法,那么自然就是输出Java程序员和程序员咯。

哦,这样啊,但是为什么会这样呀?

哈哈,这其实是涉及到了Java 方法调用的优先性问题,优先级从高到低依次是:

this.show(obj)->super.show(obj)->this.show((super)obj)->super.show((super)obj)

结合我们以上的代码来详细说一下:

例如,coder2.withMate(javacoder)coder2是一个引用变量,类型为Coder,那上面提到的this就是coder2javacoder是一个JavaCoder类型的实例,于是便有以下步骤:

  1. 在类Coder中执行withMate(JavaCoder mate)方法 -> Coder中没有这个方法;

  2. 就找他的超类->Coder也没有超类;

  3. 调用this.show((super)obj)javacoder 的超类是Coder,就是调用withMate(Coder mate),即:withMate((Coder)javacoder)Coder有这个方法,但是由于javacoder是引用自JavaCoder的一个对象,JavaCoder重写了withMate(Coder mate)方法,那自然就是调用以下代码咯:

     public void workWithMate(Coder mate) {
                System.out.println("Java程序员和程序员");
            }
    

哦哦,有意思有意思!

好了,我们今天就探讨到这里,小伙子不错,继续加油哦!

干巴爹~

更早的文章

Java接口和继承的一些知识点杂记

接口和继承的区别 不同点 接口 继承 补充说明 修饰符不同 Implements extend   是否支持多继承 支持 不支持   方法是否是抽象方法 全部是 可是可不是   抽象方法是否必须实现 是 根据需要决定 ...…

继续阅读