多态的介绍
多态
什么是多态
同一个对象(父类引用),在不同时刻(父类引用指向不同子类对象时),表现出来的不同形态(子类中重写的方法)
// Person是父类,Student和Teacher是子类
Person a1 = new Student(); // new Student();是创建了子类的对象
Person a2 = new Teacher();
a1.eat(); // Student类中的方法
a2.eat();
多态的前提
1.要有继承或实现关系
2.要有方法的重写
3.要有父类引用指向子类对象
/*
1.要有继承或实现关系
2.要有方法的重写
3.要有父类引用指向子类对象
*/
public class Test {
public static void main(String[] args) {
// 父类引用指向了子类对象
Fu fu = new Zi1();
fu.speak();
// 父类引用指向了子类对象
Fu fu1 = new Zi2();
fu1.speak();
}
}
// 父类
class Fu {
public void speak(){
System.out.println("乖儿子,叫爸爸!");
}
}
// 子类1继承了父类Fu
class Zi1 extends Fu{
@Override
public void speak() {
System.out.println("爸爸,我是儿子");
}
}
// 子类2 继承了父类Fu
class Zi2 extends Fu {
@Override
public void speak() {
System.out.println("爸爸,我是女儿");
}
}
电子产品可以玩游戏,手机和个人电脑都是电子产品.(当然,我知道并不是所有的电子产品都能玩游戏,这只是个小例子,不要在意这些)
我们分析下这个案例
手机和个人电脑都是电子产品,那么电子产品可以作为父类,手机和个人电脑可以作为子类,玩游戏是手机和个人电脑都具有的功能,但是玩游戏的类型又不同,所以可以把玩游戏这个功能作为父类的抽象方法
/*
1.要有继承或实现关系
2.要有方法的重写
3.要有父类引用指向子类对象
*/
public class Test {
public static void main(String[] args) {
// 父类的引用指向子类Phone的对象;
// new Phone();创建了子类Phone的对象
Electronics electronics = new Phone();
// 对子类方法的调用
electronics.playGames();
// 父类的引用指向了子类 NotebookComputer的对象
// new NotebookComputer();创建了子类NotebookComputer的对象
Electronics electronics1 = new NotebookComputer();
// 对子类方法的调用
electronics1.playGames();
}
}
// 抽象类
abstract class Electronics {
// 抽象方法
public abstract void playGames();
}
class Phone extends Electronics{
// 对父类中的方法进行重写
@Override
public void playGames() {
System.out.println("玩王者荣耀");
}
}
class NotebookComputer extends Electronics{
// 对父类中的方法进行重写
@Override
public void playGames() {
System.out.println("打传奇");
}
}
多态中的成员访问特点
- 构造方法
- 同继承一样,子类会通过super访问父类的构造方法
- 成员变量
- 编译看左边(父类),运行看左边(父类)
- 成员方法
- 编译看父类(左边),运行看右边(子类)
/*
当父类的引用指向子类的对象时候
以本页中的代码为例子
成员变量:编译时候看左边,运行时看左边
意思是:编译的时候,如果fu类中没有成员变量a的时候,该程序就会报错,运行的时候结果是跟随等号的左边
成员方法:编译时看左边,运行时候看右边
意思是:编译的时候,左边如果没有show方法,编译会报错,运行的结果是跟随等号的右边
*/
public class Test {
public static void main(String[] args) {
// 父类的引用指向子类的对象
Fu fu = new Zi();
// 调用成员变量给b赋值并打印输出
int b = fu.a;
System.out.println(b);
// 调用成员方法
fu.show();
}
}
// 父类
class Fu{
// 成员变量
int a = 10;
// 成员方法
public void show(){
System.out.println("我是爸爸");
}
}
// Zi类继承Fu类
class Zi extends Fu{
// 子类中的成员变量
int a = 20;
// 子类中的show方法
public void show(){
System.out.println("好吧,我是儿子");
}
}
多态的好处和弊端
好处
提高程序的扩展性
定义方法时候,使用父类类型作为参数,该方法就可以接收父类的任意子类对象(实现多态的一种方式)
弊端
不能使用子类的特有功能,(多态中成员方法的特点:编译时候看左边(父类),父类没有的方法子类中不能使用,运行时看右边(子类))
多态的应用场景之一
父类作为方法参数
public class Polymorphic {
//定义方法时候,使用父类类型作为参数,该方法就可以接收父类的任意子类对象(实现多态的一种方式)
public static void main(String[] args) {
// 多态实现,接收父类的任意子类对象
// 无论是接收Cat或者是Dog都不会报错
useAnimal(new Cat());
useAnimal(new Dog());
}
// 定义一个Animal类型的方法,以父类类型作为参数
// 该方法可以接收父类的任意子类对象
public static void useAnimal(Animal animal) {
// 上面这行代码的含义相当于 Animal animal = new Cat(); 或 Animal animal = new Dog();
//调用子类中共有的方法,不能调用每个子类的特有的方法,不然会报错
animal.eat();
//animal.watchHome(); // 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能)
//animal.catchMouse();// 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能)
}
}
//父类,抽象类,关键字abstract
abstract class Animal {
// 父类的抽象方法,子类需要重写的方法
public abstract void eat();
}
// 继承于父类Animal的Cat类
class Cat extends Animal {
// 重写父类的eat方法
@Override
public void eat() {
System.out.println("猫咪吃肉");
}
// 独属于Cat类的方法
public void catchMouse() {
System.out.println("小猫会抓老鼠");
}
}
// 继承于父类Animal的Dog类
class Dog extends Animal {
// 重写父类的eat方法
@Override
public void eat() {
System.out.println("狗狗吃肉");
}
// 独属于Dog类的方法
public void watchHome() {
System.out.println("狗狗在看家");
}
}
多态中的转型
-
向上转型
父类引用指向子类对象就是向上转型
int a = 10; double b = a;
-
向下转型
父类引用转换为子类对象
格式: 子类型 对象名 = (子类型) 父类引用;
String b = "100.0"; int a = (int)b;
代码演示:
public class Fu_And_Zi { public static void main(String[] args) { // 向上转型:父类引用指向子类对象 Fu fu = new Zi(); fu.show(); //fu.proud(); //多态的弊端,不能调用子类的成员 // 直接创建子类对象,向下转型 Zi zi = (Zi) fu; // 将Fu类 类型的对象,强转为Zi类 类型的对象 zi.proud(); // 转换成功后,就能调用子类特有的方法 } } // 创建一个Fu类 class Fu{ // Fu类的show方法 public void show(){ System.out.println("i have a son"); } } class Zi extends Fu{ // Zi类重写Fu类的show方法 @Override public void show() { System.out.println("i have a dad"); } // Zi类特有的方法 public void proud(){ System.out.println("This is my father"); } }
多态中转型存在的风险和解决方案(应用)
风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
解决方案
-
关键字
instanceof
-
使用格式
变量名 instanceof 类型
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
-
应用场景(拓展):可以用手机号或者QQ号进行登录
代码演示
public class AnimalsCode { //定义方法时候,使用父类类型作为参数,该方法就可以接收父类的任意子类对象(实现多态的一种方式) public static void main(String[] args) { // 多态实现,接收父类的任意子类对象 // 无论是接收Cat或者是Dog都不会报错 useAnimal(new Cat()); useAnimal(new Dog()); } // 定义一个Animal类型的方法,以父类类型作为参数 // 该方法可以接收父类的任意子类对象 public static Animal useAnimal(Animal animal) { // 上面这行代码的含义相当于 Animal animal = new Cat(); 或 Animal animal = new Dog(); //调用子类中共有的方法,不能调用每个子类的特有的方法,不然会报错 animal.eat(); //animal.watchHome(); // 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能) //animal.catchMouse();// 去掉注释后,这行代码会报错,因为不能使用子类特有的方法(功能) // 判断animal记录的对象是否为Dog类型,如果是,执行if语句中的内容 // instanceof判断两个对象是否为同一个类型,返回值是boolean类型 if(animal instanceof Dog){ // 将Animal类型的对象animal转换成Dog类型对象,调用Dog中特有的方法 Dog dog = (Dog) animal; dog.watchHome(); } // 返回一个对象 return animal; } } //父类,抽象类,关键字abstract abstract class Animal { // 父类的抽象方法,子类需要重写的方法 public abstract void eat(); } // 继承于父类Animal的Cat类 class Cat extends Animal { // 重写父类的eat方法 @Override public void eat() { System.out.println("猫咪吃肉"); } // 独属于Cat类的方法 public void catchMouse() { System.out.println("小猫会抓老鼠"); } } // 继承于父类Animal的Dog类 class Dog extends Animal { // 重写父类的eat方法 @Override public void eat() { System.out.println("狗狗吃肉"); } // 独属于Dog类的方法 public void watchHome() { System.out.println("狗狗在看家"); } }
小结
什么是多态
同一个对象(父类对象).在不同时刻表现出来的不同形态
多态的前提
- 要有继承或实现关系
- 要有方法的重写
- 要有父类引用指向子类的对象
多态的好处和弊端
- 好处
提高程序的拓展性,定义方法的时候,使用父类类型作为参数,该方法就可以接受父类的任意子类对象
- 弊端
不能使用子类的特有功能
多态中转型
- 风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException\
-
解决方案
-
关键字
instanceof
-
使用格式
类型1 instanceof 类型2
通俗的理解:判断关键字左边的类型,是否是右边的类型,返回boolean类型结果
-
多态常见的两种应用场景
使用父类作为方法形参,实现多态
使用父类作为返回值,实现多态
// 使用父类作为返回值,实现多态(第二种多态的实现方式)
// 创建一个Fu类
class Fu{
// Fu类的show方法
public void show(){
System.out.println("i have a son");
}
}
class Zi extends Fu{
// Zi类重写Fu类的show方法
@Override
public void show() {
System.out.println("i have a dad");
}
// Zi类特有的方法
public void proud(){
System.out.println("This is my father");
}
}
// 创建一个工厂类,使用父类类型作为返回值类型
class PersonFoctory{
public static Fu getFu(){
return new Zi();
}
}
public class Fu_And_Zi {
public static void main(String[] args) {
// 多态的实现
// 通过工厂类,类获取对象
Fu fu = PersonFoctory.getFu();
fu.show(); // 打印出的是子类的show方法,enmmm,我试过了,是真的!
}
}