一,多态的概述
1,定义
一类事物的多种形态就叫多态
eg:
水、汽、冰……本质是一种事物,但是按照某个维度去考虑,可以体现不同形态。
多态时面向对象思想的特征,和任何编程语言没有关系,只是java语言为了实现面向对象思想,
则必须在语言中实现的多态。
2,在java语言中如何实现的多态
多态是以继承为基础
多态是以防范重写为基础(如果继承中没有使用方法重写,则使用多态就失去其使用目的)。
多态的语法:
父类名称 对象名称=new 子类对象名称(参数值);
二,多态的使用目的
1,提高编码效率
2,使用多态可以使得编写的类符合设计模式中的开放封闭原则
开放封闭:是在编写类时的一种指导原则。
对扩展开放,对类的代码为了符合需要修改代码封闭。
对扩展开放:可以扩展功能(在目前的知识中可以使用继承思想)
对修改封闭:类的代码为了满足需求,尽量应该不在修改自身代码。
以上的例子中,饲养员类的代码在使用多态之前,随着动物类的增多要不停修改代码;
在使用多态以后,不管增加多少动物类,都不用修改代码。
3,为了面向接口编程做准备。
//动物类
class Animal{
String color;
int age;
public void sleep(){}
public void eatFood(){}
}
//定义猫类继承动物类
class Cat2 extends Animal{
//重写动物类中的吃东西方法
public void eatFood(){
System.out.println("猫吃鱼");
}
public void catchMouse(){}
}
//定义狗类继承动物类
class Dog2 extends Animal{
//重写动物类中的吃东西方法
public void eatFood(){
System.out.println("狗吃肉");
}
public void careRoom(){}
}
//定义猪类继承动物类
class Big2 extends Animal{
//重写动物类中的吃东西方法
public void eatFood(){
System.out.println("猪吃饲料");
}
}
//定义一个饲养员类
class SYY{
/*
//喂猫
public void FoodCat(Cat2 xx){
xx . eatFood();//猫吃食物
}
//喂狗
public void FoodDog(Dog2 xx){
xx.eatFood();//狗吃食物
}
//喂猪
public void FoodPig(Pig2 xx){
xx.eatFood();//猪吃食物
}
饲养员的代码,每养一种动物,就需要添加哪种动物的喂养方式,也就是说,这个
饲养员的类要不停的修改代码。
怎么样做到动物类添加,饲养员不用修改代码?
这是就可以使用多态去解决问题。
*/
//无论是喂猫、狗、猪还是其它动物,都叫喂动物
public void foodAnimal(Animal xx){
xx.eatFood();
}
}
public class DuoTaiDemo{
public static void main(String[] args){
//创建饲养员对象
SYY ss=new SYY();
// 创建动物类对象
//Cat2 cc=new Cat2();
//Dog2 dd=new Dog2();
//Pig2 pp=new Pig2();
//开始喂养动物
//ss.foodCat(cc);
//ss.foodDog(dd);
//ss.foodPig(pp);
//使用多态的创建对象以及使用方式
Animal cc=new Cat2();
Animal cc=new Dog2();
Animal cc=new Pig2();
//开始喂养动物
ss.foodAnimal(cc);//猫吃鱼
ss.foodAnimal(dd);//狗吃肉
ss.foodAnimal(pp);//猪吃饲料
}
}
三,多态对成员变量的影响:
1,编译时:
如果成员变量在父类存在,则在使用中才是正确的,编译时看父类
2,执行时:
执行时看父类
class Fu{
int a=10;
public void test(){
System.out.println("父类test");
}
}
class Zi extends Fu{
int b=20;
int a=30;
public void test(){
System.out.println("子类test");
}
}
public class DuoTaiDemo1{
public static void main(String[] args){
//使用多态
Fu xx=new Zi();
//开始测试成员变量
System.out.println(xx.a);//10
System.out.println(xx.b);//b不是父类的成员变量,所以编译错误,找不到。
}
}
四,多态对成员方法的影响:
1,如果父类和子类发生方法重写,那么在多态使用中也是执行子类的。
2,编译
编译时,如果调用代码中的方法在父类中存在,则正确;否则就错误。
编译时看父类。
3,执行时执行子类。
class Fu1{
public void test1(){
System.out.println("父类test1");
}
public void test2(){
System.out.println("父类test2");
}
}
class Zi1 extends Fu1{
public void test1(){
System.out.println("子类test1");
}
public void test3(){
System.out.println("子类test3");
}
}
public class DuoTaiDemo2{
public static void main(String[] args){
//使用多态
Fu1 xx=new Zi1();
//测试调用方法
xx . test1();//子类的Test1
//xx.test();//父类没有test3方法,所以编译错误
xx.test2();
}
}
五,静态绑定和动态绑定
静态绑定也叫编译期绑定
就是只看代码,不考虑执行过程,产生的类和类之间的关系。
饲养员中的喂养动物的方法,在编译期,只是饲养员类的方法和动物绑定(只知道动物类型,不清楚是什么动物)。
动态绑定也叫运行期绑定
饲养员中的喂养动物的方法,在运行期,是可以自动辨别传入的动物类的引用具体指向什么类型,这叫动态绑定。
eg:
前面的饲养员喂动物的例子
六,多态中的向上转型和向下转型
1,向上转型
在认知中,往往认为父类在上面,子类在下面(也符合常见的编码方式)
多态的语法中
父类名称 引用=new 子类名称();
上面的语句是把子类对象赋值给父类引用,就是向上转型。
所以使用多态就是是使用向上转型。
2,向下转型
强制把父类引用转为子类引用,就可以利用这个子类引用来调用子类对象的特有成员了。
语法:
子类名称 引用=(子类名称)多态中的父类引用;
class Fu2{
public void test(){
System.out.println("父类test");
}
}
class Zi2 extends Fu2{
public void test(){
System.out.println("子类test");
}
//子类的特有方法
public void test1(){
System.out.println("子类test1");
}
}
public class DuoTaiDemo3{
public static void main(String[] args){
Fu2 xx=new Zi2();
//xx . test1();错误的
//但是实际上使用多态时,创建的就是子类对象
//所以按照对象的调用成员方法的方式,应该能调用子类对象的test1方法使用。
//如果有以上需求,就是在多态中使用子类对象的特有成员
//就可以使用多态的向下转型(把父类引用强制转为子类引用)
Zi2 yy=(Zi2)xx;//执行这句代码后,xx还是父类引用,但是多了一个yy引用,指向的是子类。
yy.test1();//此时就可以使用指向子类对象的yy引用来调用子类对象的特有成员。
}
}
七,多态内存图解
class Fu3{
int a=10;
public void test(){
System.out.println("父类test");
}
}
class Zi3 extends Fu3{
int b=20;
int a=30;
public void test(){
System.out.println("子类test");
}
public void test1(){
System.out.println("子类test1");
}
}
public class DuoTaiDemo4{
public static void main(String[] args){
Fu3 xx=new Zi3();
Zi3 yy=(Zi3)xx;
}
}
八,instanceof讲解
用于多态环境,可以通过它判读某个多态引用类型的真实类型。
语法:
引用名称 instanceof 类的全名称
class Animal{
String color;
int age;
public void sleep(){}
}
class Cat extends Animal{
public void sleep(){
System.out.println("猫类重写动物类的sleep方法");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
class Dog extends Animal{
public void sleep(){
System.out.println("狗类重写动物类的sleep方法");
}
public void careRoom(){
System.out.println("狗看家");
}
}
class T{
//多态的使用
public void test(Animal xx){
//调用猫类的抓老鼠方法
//xx.catchMouse();因为使用多态,所以不能直接调用catchMouse方法
//需要向下转型
//java.long.ClassCastException 原因是在调用时虽然传入的参数是Animal类型,但是
//实际数据类型是Dog,把Dog强制转为Cat类型,肯定错误。
//以下代码执行,如果不是则会报出提示
if(!(xx instanceof Cat)){
System.out.println("传入的xx的实际类型不是Cat类型");
return;
}
Cat yy=(Cat)xx;
yy.catchMouse();
}
}
public class DuoTaiDemo5{
public static void main(String[] args){
//多态
Animal xx=new Cat();
T tt=new T();
tt.test(xx);
}
}