多态
多态介绍
Java使用多态的原因是因为它可以提高代码的灵活性和可复用性。多态是指一个对象可以具有多种形态,即不同的类或接口类型。在Java中,多态通过继承、接口和重载等机制实现。
简单的说就是一个对象有多种形态,具体点说多态就是父类中的属性和方法被子类继承后,可以具有不同的数据类型或不同的行为,使父类中的同一个属性和方法在父类与各个子类具有不同的含义。
如下图:子类都继承了父类,但同一个eat方法在不同父类子类中表现不同行为就是多态。
再比如打印机分为黑白打印机和彩色打印机,在黑白打印机情况下打出来为黑白,在彩色打印机情况下打印出来为彩色。子类(黑白打印机和彩色打印机)都继承了父类(打印机),但同一个打印方法在不同父类子类中表现不同行为(黑白,彩色)就是多态。
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
如果当前在 Flash 界面下弹出的就是 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果
多态的条件
三大条件:
- 继承:必须存在继承; extends
- 向上转型:通过父类的引用调用子类的重写的方法;
- 重写(override):又称覆盖,在子类中创建一个与父类具有相同的返回值类型、方法名、参数列表的方法,以实现与父类不同的行为。
多态的格式
父类类型 变量名 = new 子类类型();
然后通过 变量名.方法名()调用在子类中重写的方法
多态的例子
public class Animal {
public void eat(){
System.out.println("Animal eat");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("cat eat");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("dog eat");
}
public static void main(String[] args) {
Animal an = new Dog();
Animal an1 = new Cat();
an.eat();
an1.eat();
}
}
举个栗子,一只鸡可以做成白切鸡、豉油鸡、吊烧鸡、茶油鸡、盐焗鸡、葱油鸡、手撕鸡、清蒸鸡、叫花鸡、啤酒鸡、口水鸡、香菇滑鸡、盐水鸡、啫啫滑鸡、鸡公煲等等。
class Chicken{
public void live(){
System.out.println("这是一只鸡");
} }
重写live方法,建立白切鸡类
class BaiqieChicken extends Chicken{
public void live(){
System.out.println("这是一只会被做成白切鸡的鸡"); } }
main方法里调用
Chicken c = new BaiqieChicken(); c.live();
class JiaoHuaChicken extends Chicken{
public void live(){
System.out.println("这是一只会被做成叫花鸡的鸡"); } }
Chicken c = new JiaoHuaChicken (); c.live();
练习打印机类PrintMachine 彩色打印机类ColorPrint,黑白打印机类HbPrint,都有print方法。Test实现多态
转型
将一个类型转换成另一个类型的过程被称为类型转换。 我们所说的对象类型转换,一般是指两个存在继承关系的对象,而不是任意类型的对象。如果两个类型之间没有继承关系,就不允许进行类型转换,否则会抛出强制类型转换异常(java.lang.ClassCastException)。
Java语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换。Java中引用类型之间的类型转换(前提是两个类是直接或间接的父子关系)主要有两种,分别是向上转型(upcasting)和向下转型(downcasting) 。
我们先来看下面这张图:
猫、狗、牛、羊都是动物,所以”动物“是父类,猫狗牛羊是具体的子类。我们可以说猫是动物,狗是动物,牛是动物,羊是动物,这个结论肯定没错!但如果我们说,动物是猫,动物是狗,动物是牛,动物是羊,这个结论一定正确吗?那可就不一定了。子类肯定符合父类类型,但反之,父类不一定符合子类类型!
接下来分别对向上转型和向下转型进行讲解。
向上转型
实际上就是创建一个子类对象,将其当作父类对象来使用。所谓的向上转型,就是父类引用指向子类的对象,也就是把子类对象直接赋给父类引用变量,此时不用强制转换。比如我们说猫是动物,狗是动物,牛是动物,羊是动物,这就是把子类当成父类来用。父类是子类的上级,我们直接把子类向上提拔转型了。
格式: 父类类型 对象名 = new 子类类型();
向上转型具有如下特点:
- 编译类型取决于=号左边,运行类型取决于=号右边;
- 子类可以调用父类的所有成员,但需遵守访问权限;
- 父类不能调用子类的特有成员;
- 最终的运行效果取决于子类的具体实现。
使用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作
Animal cat = new Cat();
//向上转型,将Cat类型转换为Animal类型,小范围向大范围的转换
代码
class Aminal {
public void display() {
System.out.println("Animal");
}
}
class Cat extends Aminal {
public void display() {
System.out.println("Cat");
}
}
class Dog extends Aminal {
public void display() {
System.out.println("Dog");
}
}
public class Main{
public static void main(String[] args) {
Aminal aminal1 = new Aminal();
Aminal aminal2 = new Cat();
Aminal aminal3 = new Dog();
aminal1.display();
aminal2.display();
aminal3.display();
}
}
优点:让代码实现更简单灵活
缺点:不能调用到子类特有的方法
例如
class Animal {
public void display() {
System.out.println("Animal");
}
}
class Dog extends Animal {
public void display() {
System.out.println("dog");
}
public void eat() {
System.out.println("吃骨头");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
animal.display();
animal.eat(); //会报错
}
}
向下转型
向下转型:在 Java 中,向下转型(Downcasting)是与向上转型相对的概念,向上转型是将子类对象的引用赋值给父类类型的变量,而向下转型则是将父类类型的引用强制转换为子类类型的引用。通俗来讲就是将一个子类对象向上转型之后可以当成父类对象使用,若需要调用子类特有的方法,则需要将父类对象再还原为子类对象。这就称作向下转型。
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
当子类对象向上转型后,将无法调用子类中的方法,如果我们想调用子类特有的方法,我们就可以使用向下转型,将父类引用还原成子类对象即可。
class Animal {
public void display() {
System.out.println("Animal");
}
}
class Dog extends Animal {
public void display() {
System.out.println("dog");
}
public void eat() {
System.out.println("吃骨头");
}
}
public class Main{
public static void main(String[] args) {
//向上转型
Animal animal = new Dog();
animal.display();
//向下转型
//Animal类中原本没有 eat方法,在向下转型之前如果调用eat方法会报错
//向下转型为子类Dog类后,就可以调用子类中特有的方法,而不会报错
animal = (Dog)animal;
((Dog) animal).eat();
}
}
向下转型有的时候不太安全
例如:一个狗类对象向上转型转换为动物类,在向下转型的时候不一定转换为狗类,可能转换为猫类等,所以当我们向下转型的时候要加上强制转换符。
有的时候也会造成抛出异常,所以Java中引入了instanceof,如果结果为true,则可以安全转换。
Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换
class Animal {
public void display() {
System.out.println("Animal");
}
}
class Dog extends Animal {
public void display() {
System.out.println("dog");
}
public void eat() {
System.out.println("吃骨头");
}
}
public class Main {
public static void main(String[] args) {
//向上转型
Animal animal = new Dog();
//判断instanceof 是否为 true
if(animal instanceof Dog) {
//向下转型
animal = (Dog)animal;
((Dog) animal).eat();
} else {
System.out.println("Animal无法向下转型为Dog");
}
}
}