相信大家对于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
就是coder2
,javacoder
是一个JavaCoder
类型的实例,于是便有以下步骤:
在类
Coder
中执行withMate(JavaCoder mate)
方法 ->Coder
中没有这个方法;就找他的超类->
Coder
也没有超类;调用
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程序员和程序员"); }
哦哦,有意思有意思!
好了,我们今天就探讨到这里,小伙子不错,继续加油哦!
干巴爹~