面向对象-多态

多态(掌握)

(1)同一个对象在不同时刻体现出来的不同状态。

(2)多态的前提:

    A:有继承或者实现关系。

    B:有方法重写。

    C:有父类或者父接口引用指向子类对象。

    多态的分类:

        a:具体类多态

            class Fu {}

            class Zi extends Fu {}

            Fu f = new Zi();

        b:抽象类多态

            abstract class Fu {}

            class Zi extends Fu {}

            Fu f = new Zi();

        c:接口多态

            interface Fu {}

            class Zi implements Fu {}

            Fu f = new Zi();

(3)多态中的成员访问特点

    A:成员变量

        编译看左边,运行看左边

    B:构造方法

        子类的构造都会默认访问父类构造

    C:成员方法

        编译看左边,运行看右边

    D:静态方法

        编译看左边,运行看左边


/*
	多态:同一个对象(事物),在不同时刻体现出来的不同状态。
	举例:
		猫是猫,猫是动物。
		水(液体,固体,气态)。
		
	多态的前提:
		A:要有继承关系。
		B:要有方法重写。
			其实没有也是可以的,但是如果没有这个就没有意义。
				动物 d = new 猫();
				d.show();
				动物 d = new 狗();
				d.show();
		C:要有父类引用指向子类对象。
			父 f =  new 子();
			
	用代码体现一下多态。
	
	多态中的成员访问特点:变量没有重写,用的还是父亲的;因为方法有重写,父类方法被子类覆盖掉了,只留下子类的方法
		A:成员变量
			编译看左边,运行看左边。
		B:构造方法
			创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
		C:成员方法
			编译看左边,运行看右边。
		D:静态方法
			编译看左边,运行看左边。
			(静态和类相关,算不上重写,所以,访问还是左边的)
			
		由于成员方法存在方法重写,所以它运行看右边。
*/
public class Fu {
	public int num = 100;

	public void show() {
		System.out.println("show Fu");
	}

	public static void function() {
		System.out.println("function Fu");
	}
}

public class Zi extends Fu {
	public int num = 1000;
	public int num2 = 200;

	public void show() {
		System.out.println("show Zi");
	}
	
	public void method() {
		System.out.println("method zi");
	}
	
	public static void function() {
		System.out.println("function Zi");
	}
}

public class DuoTaiDemo {
	
	public static void main(String[] args) {
		//要有父类引用指向子类对象。
		//父 f =  new 子();
		Fu f = new Zi();
		System.out.println(f.num);   //100
		//System.out.println(f.num2);//报错:找不到符号
		
		f.show();     //show Zi
		//f.method(); //报错:找不到符号
		f.function(); //function Fu
	}

}

(4)多态的好处:

    A:提高代码的维护性(继承体现)

    B:提高代码的扩展性(多态体现)


/*
	多态的好处:
		A:提高了代码的维护性(继承保证)
		B:提高了代码的扩展性(由多态保证)
		
	猫狗案例代码
*/
class Animal {
	public void eat(){
		System.out.println("eat");
	}
	
	public void sleep(){
		System.out.println("sleep");
	}
}

class Dog extends Animal {
	public void eat(){
		System.out.println("狗吃肉");
	}
	
	public void sleep(){
		System.out.println("狗站着睡觉");
	}
}

class Cat extends Animal {
	public void eat() {
		System.out.println("猫吃鱼");
	}
	
	public void sleep() {
		System.out.println("猫趴着睡觉");
	}
}

class Pig extends Animal {
	public void eat() {
		System.out.println("猪吃白菜");
	}
	
	public void sleep() {
		System.out.println("猪侧着睡");
	}
}

//针对动物操作的工具类
class AnimalTool {
	private AnimalTool(){}

	/*
	//调用猫的功能
	public static void useCat(Cat c) {
		c.eat();
		c.sleep();
	}
	
	//调用狗的功能
	public static void useDog(Dog d) {
		d.eat();
		d.sleep();
	}
	
	//调用猪的功能
	public static void usePig(Pig p) {
		p.eat();
		p.sleep();
	}
	*/
	public static void useAnimal(Animal a) {
		a.eat();
		a.sleep();
	}
	
}

class DuoTaiDemo2 {
	public static void main(String[] args) {
		//我喜欢猫,就养了一只
		Cat c = new Cat();
		c.eat();
		c.sleep();
		
		//我很喜欢猫,所以,又养了一只
		Cat c2 = new Cat();
		c2.eat();
		c2.sleep();
		
		//我特别喜欢猫,又养了一只
		Cat c3 = new Cat();
		c3.eat();
		c3.sleep();
		//...
		System.out.println("--------------");
		/*
		问题来了,我养了很多只猫,每次创建对象是可以接受的
		但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。
		我们准备改进
		*/
		//useCat(c);
		//useCat(c2);
		//useCat(c3);
		
		//AnimalTool.useCat(c);
		//AnimalTool.useCat(c2);
		//AnimalTool.useCat(c3);
		
		AnimalTool.useAnimal(c);
		AnimalTool.useAnimal(c2);
		AnimalTool.useAnimal(c3);
		System.out.println("--------------");
		
		//我喜欢狗
		Dog d = new Dog();
		Dog d2 = new Dog();
		Dog d3 = new Dog();
		//AnimalTool.useDog(d);
		//AnimalTool.useDog(d2);
		//AnimalTool.useDog(d3);
		AnimalTool.useAnimal(d);
		AnimalTool.useAnimal(d2);
		AnimalTool.useAnimal(d3);
		System.out.println("--------------");
		
		//我喜欢宠物猪
		//定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用
		Pig p = new Pig();
		Pig p2 = new Pig();
		Pig p3 = new Pig();
		//AnimalTool.usePig(p);
		//AnimalTool.usePig(p2);
		//AnimalTool.usePig(p3);
		AnimalTool.useAnimal(p);
		AnimalTool.useAnimal(p2);
		AnimalTool.useAnimal(p3);
		System.out.println("--------------");
		
		/*
		我喜欢宠物狼,老虎,豹子...
		定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用
		前面几个必须写,我是没有意见的
		但是,工具类每次都改,麻烦不
		我就想,你能不能不改了
		太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢?
		改用另一种解决方案。
		public static void useAnimal(Animal a) {
			a.eat();
			a.sleep();
		}
		*/
		
	}
	
}

(5)多态的弊端:

    父不能使用子的特有功能。

    现象:

        子可以当作父使用,父不能当作子使用。


/*
	多态的弊端:
		不能使用子类的特有功能。
*/
class Fu {
	public void show() {
		System.out.println("show fu");
	}
}

class Zi extends Fu {
	public void show() {
		System.out.println("show zi");
	}
	
	public void method() {
		System.out.println("method zi");
	}

}

class DuoTaiDemo3 {
	public static void main(String[] args) {
		//测试
		Fu f = new Zi();
		f.show();  //show zi
		f.method();//报错:方法未定义
	}
}

(6)多态中的转型

    A:向上转型

        从子到父,父类引用指向子类对象:Fu f = new Zi();

    B:向下转型

        从父到子,父类引用转为子类对象:Zi  z = (Zi)f;


/*
	多态的弊端:
		不能使用子类的特有功能。
		
	我就想使用子类的特有功能?行不行?
		行。
		
	怎么用呢?
		A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
		B:把父类的引用强制转换为子类的引用。(向下转型)
		
	对象间的转型问题:
		向上转型:
			Fu f = new Zi();
		向下转型:
			Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。
*/
class Fu {
	public void show() {
		System.out.println("show fu");
	}
}

class Zi extends Fu {
	public void show() {
		System.out.println("show zi");
	}
	
	public void method() {
		System.out.println("method zi");
	}

}

class DuoTaiDemo4 {
	public static void main(String[] args) {
		//测试
		Fu f = new Zi();
		f.show();  //show zi
		//f.method();//报错:方法未定义
		
		//创建子类对象,可以,但是很多时候不合理。而且,太占内存了。
		//Zi z = new Zi();
		//z.show();
		//z.method();
		
		//你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢?
		//如果可以,代码如下:
		//向下转型
		Zi z = (Zi)f;
		z.show();  //show zi
		z.method();//method zi
	}
}

(7)孔子装爹的案例帮助大家理解多态

多态的问题理解:
	class 孔子爹 {
		public int age = 40;
		
		public void teach() {
			System.out.println("讲解JavaSE");
		}
	}
	
	class 孔子 extends 孔子爹 {
		public int age = 20;
		
		public void teach() {
			System.out.println("讲解论语");
		}
		
		public void playGame() {
			System.out.println("英雄联盟");
		}
	}
	
	//Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了
	//但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?
	//然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹
	//向上转型
	孔子爹 k爹 = new 孔子();
	//到人家那里去了
	System.out.println(k爹.age);      //40
	System.out.println(k爹.teach());  //讲解论语
	//k爹.playGame();                 //这不行,这是儿子才能做的
	
	
	//讲完了,下班回家了,脱下爹的装备,换上自己的装备
	//向下转型
	孔子 k = (孔子) k爹; 
	System.out.println(k.age); //20
	k.teach();                 //讲解论语
	k.playGame();              //英雄联盟


补充:多态继承中的内存图解


补充:一般在多态的向下转型中容易出现ClassCastException:类型转换异常



/*
	ClassCastException:类型转换异常
	一般在多态的向下转型中容易出现
*/
class Animal {
	public void eat(){}
}

class Dog extends Animal {
	public void eat() {}
	
	public void lookDoor() {
	
	}
}

class Cat extends Animal {
	public void eat() {
	
	}
	
	public void playGame() {
		
	}
}

class DuoTaiDemo5 {
	public static void main(String[] args) {
		//内存中的是狗
		Animal a = new Dog();
		Dog d = (Dog)a;
		
		//内存中是猫
		a = new Cat();
		Cat c = (Cat)a;
		
		//内存中是猫
		Dog dd = (Dog)a; //ClassCastException
	}
}

(8)多态的练习


/*
	多态练习:猫狗案例
*/
class Animal {
	public void eat(){
		System.out.println("吃饭");
	}
}

class Dog extends Animal {
	public void eat() {
		System.out.println("狗吃肉");
	}
	
	public void lookDoor() {
		System.out.println("狗看门");
	}
}

class Cat extends Animal {
	public void eat() {
		System.out.println("猫吃鱼");
	}
	
	public void playGame() {
		System.out.println("猫捉迷藏");
	}
}

class DuoTaiTest {
	public static void main(String[] args) {
		//定义为狗
		Animal a = new Dog();
		a.eat();//狗吃肉

		//还原成狗
		Dog d = (Dog)a;
		d.eat();     //狗吃肉
		d.lookDoor();//狗看门

		//变成猫
		a = new Cat();
		a.eat();//猫吃鱼

		//还原成猫
		Cat c = (Cat)a;
		c.eat();     //猫吃鱼
		c.playGame();//猫捉迷藏

		
		//演示错误的内容
		//Dog dd = new Animal();//不兼容的类型
		//Dog ddd = new Cat();  //不兼容的类型
		
		//Dog dd = (Dog)a;      //ClassCastException
		
	}
}	


/*
	不同地方饮食文化不同的案例
*/
class Person {
	public void eat() {
		System.out.println("吃饭");
	}
}

class SouthPerson extends Person {
	public void eat() {
		System.out.println("炒菜,吃米饭");
	}
	
	public void jingShang() {
		System.out.println("经商");
	}
}

class NorthPerson extends Person {
	public void eat() {
		System.out.println("炖菜,吃馒头");
	}
	
	public void yanJiu() {
		System.out.println("研究");
	}
}

class DuoTaiTest2 {
	public static void main(String[] args) {
		//测试
		//南方人
		Person p = new SouthPerson();
		p.eat();         //炒菜,吃米饭

		SouthPerson sp = (SouthPerson)p;
		sp.eat();        //炒菜,吃米饭
		sp.jingShang();  //经商

		
		//北方人
		p = new NorthPerson();
		p.eat();         //炖菜,吃馒头

		NorthPerson np = (NorthPerson)p;
		np.eat();        //炖菜,吃馒头
		np.yanJiu();     //研究
	}
}

看程序写结果:

/*
	看程序写结果:先判断有没有问题,如果没有,写出结果
	
	多态的成员访问特点:
		方法:编译看左边,运行看右边。
		
	继承的时候:
		子类中有和父类中一样的方法,叫重写。
		子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
class A {
	public void show() {
		show2();
	}
	public void show2() {
		System.out.println("我");
	}
}
class B extends A {
	/*可以理解存在该代码,因为继承了父类的方法
	public void show() {
		show2();
	}
	*/

	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();  //爱
		
		B b = new C();
		b.show();  //你
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZHOU_VIP

您的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值