JavaSE笔记12 多态
一.多态的概述:
面向对象的三大特征:封装,继承,多态
多态作为三大特征之一,指的是在不同的时刻,所表现出的不同的状态
举例: Cat c=new Cat();
Animal a=new Cat();
猫可以是猫的类型,即:猫 m = new 猫();
同时猫也是动物的一种,也可以把猫称为动物,即:动物 d = new 猫();
即:使用父类的引用去接受子类的对象
二.多态的产生条件:
多态的产生条件共有三条:
- 要有继承关系
- 要有方法重写,其实没有也是可以的,但是如果没有这个就没有意义
- 要有父类引用指向子类对象,即:父 f = new 子();
代码演示:
public class Test {
public static void main(String[] args) {
//多态的语法:父类引用指向子类对象
Animal animal = new Cat();
animal.eat();
animal.sleep();
System.out.println("============");
animal = new Dog();
animal.eat();
animal.sleep();
}
}
//父类:将子类中共有的的成员进行抽取
class Animal{
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
//子类:猫类
class Cat extends Animal{
public void catchMouse(){
System.out.println("猫抓老鼠");
}
//对父类中的方法进行重写
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫喜欢躺在温暖的地方睡觉");
}
}
//子类:狗类
class Dog extends Animal{
public void lookDoor(){
System.out.println("狗看门");
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗喜欢晚睡");
}
}
三.多态的成员访问特点:
多态中的成员访问特点:
- 成员变量: 编译看左边,运行看左边
- 构造方法: 创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化
- 成员方法: 编译看左边,运行看右边
- 静态方法: 编译看左边,运行看左边 (静态和类相关,算不上重写,所以,访问还是左边的)
代码演示:
public class MyTest {
public static void main(String[] args) {
//之前的方式
/* Cat cat = new Cat();
cat.sleep();
cat.eat();
cat.catchMouse();*/
//多态的方式
Animal an = new Cat();
//多态要有方法重写,从语法层面来说你不重写,语法不报错,但是多态就没有意义了。
an.eat(); //子类重写了父类的方法,多态的形式去调用,以子类重写过后的为准
//多态形式调用成员方法:编译看左边,运行看右边 Animal an = new Cat();
//即左边没有的成员方法不能调用,调用会报错,运行时看子类中的重写结果
//多态形式访问成员变量:编译看左边,运行也看左边,实际上成员变量访问的都是父类
int num = an.num;
System.out.println(num);
//多态形式创建对象,还是先初始父类数据,再初始化自己
Animal.show();
Cat.show();
}
}
class Animal {
String name;
int age;
int num = 20;
public Animal() {
System.out.println("父类的构造方法执行了");
}
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
public static void show() {
System.out.println("fu show");
}
}
class Cat extends Animal {
int num = 100;
public Cat() {
System.out.println("cat的构造方法执行了");
}
@Override
public void eat() {
System.out.println("猫爱吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
public static void show() {
System.out.println("zi show");
}
}
class Dog extends Animal {
public void lookDoor() {
System.out.println("狗看门");
}
}
四.多态的意义:
多态最大的意义在于:对应继承提高了代码的维护性,多态则提高了代码的扩展性
对于多态的扩展性的代码演示:
package DuoTaiDemo;
public class TestDuoTai {
public static void main(String[] args) {
Animal an = new Cat();
an.eat();
System.out.println("-----------test Duo Tai--------------");
Animal animal = new Cat();
System.out.println(animal.num);
Animal.show();
Cat.show();
System.out.println("------------test Xiang Xia-------------");
Cat cat = (Cat) an;
System.out.println(cat.num);
cat.eat();
cat.CatchMouse();
System.out.println("------------Duo Tai Apply--------------");
Cat ex1 = new Cat();
MyutilsTestEat.TestEat(ex1);
Dog ex2 = new Dog();
MyutilsTestEat.TestEat(ex2);
MyutilsTestEat.TestEat(new Animal());
}
}
class Animal{
String name;
int age;
int num=200;
public Animal(){
System.out.println("父类空参构造");
}
public void eat(){
System.out.print("爱吃");
}
public static void show(){
System.out.println("Father show");
}
}
class Cat extends Animal{
int num=20;
public Cat(){
System.out.println("Cat类空参构造");
}
@Override
public void eat() {
super.eat();
System.out.println("鱼");
}
public void CatchMouse(){
System.out.println("抓老鼠");
}
public static void show(){
System.out.println("Son show");
}
}
class Dog extends Animal{
int num=2;
public Dog(){
System.out.println("Dog类空参构造");
}
@Override
public void eat() {
super.eat();
System.out.println("骨头");
}
public void lookDoor(){
System.out.println("看门");
}
public static void show(){
System.out.println("Son Dog Show");
}
}
class MyutilsTestEat{
private MyutilsTestEat(){}
//Animal an = Cat cat
//Animal an = Dog dog
public static void TestEat(Animal an){
an.eat();
}
public static void TestEat(Cat cat){
cat.eat();
}
public static void TestEat(Dog dog){
dog.eat();
}
}
五.多态的弊端以及向下转型:
多态的存在提高了代码的复用性与维护性,以及提高代码的可扩展性。但多态也存在着弊端,不能访问子类中特有的功能。想要进行访问子类中特有的功能,需要进项向下转型
代码演示向下转型:
public class MyTest {
public static void main(String[] args) {
/* Animal an = new Cat(); //多态就是向上转型。
an.eat();
System.out.println(an.num);//
//多态的形式,不能直接调用子类特有的功能
//an.catchMouse();
//如果你要调用子类特有的方法,你可以向下转型,你可以把父类引用,转换成子类对象
Cat cat = (Cat) an; //向下转型。
System.out.println(cat.num);
cat.catchMouse();
*/
System.out.println("====================================");
Animal an = new Cat();
an.eat();
//向下转型
Cat cat = (Cat) an;
cat.catchMouse();
//类型转换异常。ClassCastException
// org.westos.demo5.Cat cannot be cast to org.westos.demo5.Dog
an = new Dog();
Dog dog = (Dog) an;
dog.lookDoor();
}
}
class Animal {
int num = 20;
public void eat() {
System.out.println("吃饭");
}
}
class Cat extends Animal {
int num = 500;
int age = 2;
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
class Dog extends Animal {
int num = 900;
int age = 800;
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void lookDoor() {
System.out.println("狗看门");
}
}
六.多态练习题:
题设1: 孔子装爹:
孔子爹是一名java讲师,有天张三请孔子爹去自己家讲java,家中只有孔子一人,过一会李四也去孔子爹他家了,孔子一看来生意了,不想失去赚钱的机会,于是乔装打扮成他爹,去教了论语,完事之后孔子又做回自己打游戏去了
题目分析:
使用多态中的知识进行解决,首先出现继承关系:即孔子继承孔子爹,并且设定两类的成员变量,如父子年龄,还有父亲特有的教java,在孔子类中需重写为教论语,并且对于孔子还有一个特有方法就是打游戏,所以需要向下转型来让孔子在教完之后做回自己
源代码:
/*
题目:孔子装爹:
孔子爹是一名java讲师,有天张三请孔子爹去自己家讲java,家中只有孔子一人,过一会李四也去孔子爹他家了,孔子
一看来生意了,不想失去赚钱的机会,于是乔装打扮成他爹,去教了论语,完事之后孔子又做回自己打游戏去了
*/
public class DuoTaiPractice {
public static void main(String[] args) {
//演绎故事
//装爹用多态
KongziFather kzf = new Kongzi();
System.out.println("孔子装爹,"+kzf.age+"岁");
kzf.teach();
//做回自己,向下转型
Kongzi kong = (Kongzi) kzf;
System.out.println("做回孔子,"+kong.age+"岁");
kong.playGame();
}
}
class KongziFather{
int age = 50;
public void teach() {
System.out.println("讲授java");
}
}
class Kongzi extends KongziFather{
int age = 20;
@Override
public void teach() {
System.out.println("讲授《论语》");
}
public void playGame(){
System.out.println("爱玩游戏");
}
}
运行截图:
题设2: 看下面程序是否有问题,如果没有,说出结果:
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show(); //输出1
B b = new C();
b.show(); //输出2
}
}
解答:
该程序首先没有错,在执行主方法时,a.show()调的方法实际上在编译时是看A中有没有show方法,显然A中有,并且方法体是show2,这时候运行时调用的是B中的show2方法,所以输出1是:爱
对于第二个输出,还是编译的时候看b中没有会向上找,在类A中找到了,所以编译会通过,执行时实际上执行的是C类中的show2方法,所以输出2是:你
七.关于多态的总结:
- 多态:一种事物,在不同的时刻所表现出的不同状态
- 多态的前提要有继承关系,语法想表现形式为:父类引用指向子类对象
- 多态的好处:提高代码的复用性与维护性,同时主要提高代码的扩展性
- 多态的弊端:不能直接调用子类特有的功能,想要访问子类特有功能,可以进行向下转型的操作
多态访问成员的特点:
- 访问成员变量,编译看左边(父类),运行看左边(父类)
- 访问成员方法,子类重写父类中的方法,编译看左边(父类),运行看右边(子类)
- 访问静态方法,静态方法不参与方法重写,编译看左边(父类),运行看左边(父类)
多态的内存图演示: