Java
中的多态是三大特性中的一个比较重要的特性,《Java编程思想》中用了一个极度简单的话形容多态。
多态通过分离做什么和怎么做来达到灵活编程的目的。
多态存在是有一定条件的,主要有三个核心条件:
类之间要有继承关系。【无继承,何谈多态】
子类要重写父类的方法。【子类要有自己的思想】
父类引用指向子类对象。【这一点尤其重要,稍后加以阐述】
首先从例子出发,讲讲多态怎么玩?
定义一个父类,简单粗暴就叫做Father类吧
有两个属性:
一个成员变量age,一个静态成员变量name。
三个方法
一个静态方法、两个非静态方法
public class Father {
int age = 68;
static String name = "yourFather";
public void playChess () {
System.out.println("父亲下象棋……");
}
public static void sleep () {
System.out.println("父亲睡觉……");
}
public void playGame () {
System.out.println("father打游戏……");
}
public void eat () {
System.out.println("父亲吃饭……");
}
}
定义一个子类,Son
有三个属性:
两个从父类继承的属性:age、name,一个子类独有的属性hight。
三个方法:
一个从父类继承的方法(eat)、两个子类独有的方法playGame()、sleep()
class Son extends Father {
int age = 20;
static String name = "小明";
Integer hight = 178;
int id = 123456;
public void playGame () {
System.out.println("小明打游戏……");
}
public void eat () {
System.out.println("小明吃饭……");
}
public static void sleep () {
System.out.println("小明睡觉……");
}
}
测试类
public class Test0201 {
public static void main(String[] args) {
// 记住,这一行是关键
Father father = new Son();
System.out.println("没有重写父类方法:");
//没有重写父类方法
father.playChess();
System.out.println();
System.out.println("重写父类方法:");
//重写父类方法
father.playGame();
father.eat();
System.out.println();
System.out.println("静态方法:");
father.sleep(); // 这里默认编译不规范,静态方法建议用 类.方法() 调用
System.out.println();
System.out.println(father.age);
System.out.println(father.name);
System.out.println(((Son) father).hight);
System.out.println(((Son) father).id);
System.out.println("*******************");
Son son = (Son) father;
son.eat();
son.playGame();
son.playChess();
son.sleep();
System.out.println(son.age);
System.out.println(son.hight);
System.out.println(son.name);
}
}
Father father = new Son();
如上图所示,栈中的引用father
,指向了位于堆中的对象new Son()
,这就是上面所说的父类引用指向子类对象。
看看下面的运行结果:
没有重写父类方法:
父亲下象棋……【father.playChess();是父类方法独有的方法,子类没有重写,因此调用的是父类的方法】
重写父类方法:
小明打游戏……【father.eat();由于子类重写了,因此默认调用子类的方法】
小明吃饭……
静态方法:
父亲睡觉……【sleep()是一个静态方法,实现了自己的逻辑,默认调用父类的方法】
68【直接采用父类的属性】
yourFather【直接采用父类属性】
178
123456
*******************
小明吃饭……
小明打游戏……
父亲下象棋……【子类没有该方法,只能用父类的方法】
小明睡觉……【调用子类静态方法】
20
178
小明
结论:
对于成员变量
编译看左边,运行看左边。(看父类的属性)
对于成员方法
编译看左边,运行看右边。(这就是多态的核心,只有运行的时候才知道调用的是哪个类,这就是为什么编程思想中说"多态决定的是怎么做")
对于静态方法
编译看左边(父类),运行看左边(父类)。(取决于父类怎么运行的,其实本质上是没有重写父类方法的)
如果强制将父类引用指向子类,则所有的调用方法和属性都是调用子类的,本质是在内存的栈引用(son
引用)指向子类对象。
内存结构如下:
看到这里,可以发现多态的好处,可以用两个引用指向同一个对象,减少了重复创建对象的过程,很好的解决对象泛滥的问题,有利于方法的横向扩展。
关于多态,其核心主要在于什么是父类引用指向子类对象,核心是执行时是依据哪个对象重写的逻辑执行。【课本通俗的称为动态绑定】