java复习系列文章目录
前言
学习Java已有一段时间,很多内容不免有遗忘和疏漏之处,此系列文章便是对Java各方面内容复习的总结
一、多态是什么?
多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译的时候并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪一个类的实例对象,该引用变量发出的方法调用到底是哪一个类中的方法,必须在程序运行期间才能决定!
二、两种多态方式
- 对于Java语言,多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。
- 运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。
三、 实现多态的条件
Java实现多态有三个必要条件:继承、重写、向上转型
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重写,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备既能调用父类的方法又能调用子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同动作的行为。
对于Java而言,多态的实现机制遵循一个原则:当超类对象的引用变量引用子类对象时,调用被引用对象的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类重写的方法。
四、实现形式
在Java中有两种形式可以实现多态。继承和接口。
1. 继承
package com.lxy.test;
/**
* @Author: ManTou
* @Description:
* @Date: Created in 22:45 2021/3/14
*/
class Father{
void fun1() {
System.out.println("被继承类");
}
void fun2() {
System.out.println("被继承类2");
}
}
class Son extends Father {//Son类继承Father类
@Override
void fun1() {//子类重写的父类中的方法
System.out.println("继承类");
}
void fun2(String s) {//重载而没有重写
System.out.println("被继承类" + s);
}
void fun3(){
//任意代码
}
}
public class Test {
public static void main(String[] args) {
Father what = new Son();
what.fun1();//父类中存在且子类重写了此方法,所以执行子类中的方法
what.fun2();//父类中存在但子类重载了此方法(重载,没有重写),所以执行父类中的方法
//由于存在继承关系,子类中特有的方法会被隐藏(hide),所以下行代码无法执行
what.fun3();
}
}
输出:
继承类
被继承类2
2. 接口
个人认为站在多态角度看这两种方式其实是一样的
package com.lxy.test;
/**
* @Author: ManTou
* @Description:
* @Date: Created in 23:24 2021/3/14
*/
public interface Father2 {
void fun();
}
class Son2 implements Father2{
@Override
public void fun() {
System.out.println("son2");
}
}
class Son3 implements Father2{
@Override
public void fun() {
System.out.println("son3");
}
}
class Son4 implements Father2{
@Override
public void fun() {
System.out.println("son4");
}
}
class Test2 {
public static void main(String[] args) {
Father2 what = new Son2();
what.fun();
Father2 the = new Son3();
the.fun();
Father2 fuck = new Son4();
fuck.fun();
}
}
输出:
Son2
Son3
son4
五、一个例子
前置知识:其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
package com.lxy.test;
/**
* @Author: ManTou
* @Description:
* @Date: Created in 22:45 2021/3/14
*/
class A {
public String show(A obj) {
return ("A and A");
}
public String show(D obj) {
return ("A and D");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
@Override
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
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
A,B,C,D四个类存在如下关系:
优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
分析:前三行:按照上述优先级分析,
此时this是a1,传进变量是B类型,this.show(O)没有匹配,
继续下一优先级:super.show(O),this是A,传进变量是B类型,A类的父类是Object类,Object同样没有这个方法,
继续下一优先级:this.show((super)O),this是A,传进变量是B类型,B类的父类是A类,此时可以匹配A类中的**public String show(A obj){}**方法,所以输出是A and A,第二行同理
中间三行:
第四行:首先,由于继承关系的存在,a2实例永远无法调用方法:public String show(B obj)。
然后继续根据优先级分析,此时this是a2,传入变量类型是B类型
先看最高优先级this.show(O),A类中的方法public String show(A obj)
和 public String show(D obj) 的参数与传入的参数类型不匹配(因为传入的参数类型是B类型)
继续下一优先级super.show(O),A类的父类是Object,不匹配
继续下一优先级this.show((super)O),B类的父类是A,和A类的方法 public String show(A obj) 相匹配,但是,此方法被其子类重写了,所以会执行子类中的同名方法,所以会输出 B and A
第五行:同第四行
第六行:此时this是a2,传入变量类型是D类型
先看最高优先级this.show(O),A类中的方法 public String show(D obj) 的参数与传入的参数类型相匹配且子类也没有重写此方法,所以执行此方法,输出A and D。(这行其实同第三行,但是我懒得写了)
第七行:此时this是b,传入变量类型是B类型
先看最高优先级this.show(O),B类中的方法 public String show(B obj)的参数与传入的参数类型相匹配且子类也没有重写此方法,所以执行此方法,输出B and B
第八行:此时this是b,传入变量类型是B类型
先看最高优先级this.show(O),B类中的方法 public String show(B obj)和public String show(A obj)的参数与传入的参数类型不匹配(因为传入的参数类型是C类型)
继续下一优先级super.show(O),B类的父类是A类,A类中也没有与之相匹配的函数
继续下一优先级this.show((super)O),B类的父类是B类,相匹配,所以执行方法public String show(B obj),输出B and B
第九行:此时this是b,传入变量类型是B类型
先看最高优先级this.show(O),B类中的方法 public String show(B obj)和public String show(A obj)的参数与传入的参数类型不匹配(因为传入的参数类型是D类型)
继续下一优先级super.show(O),B类的父类是A类,A类中有与之相匹配的方法public String show(D obj),所以执行此方法,输出A and D。
总结
- 多态有两种实现方式:继承和接口
- 在继承关系中,子类特有的方法会被隐藏起来(即只会执行和父类同名的方法)
- 继承链中方法调用的优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。