多态
简单理解
某一事物,在不同时刻表现出来的不同状态
例如:
水:
固态、液态、气态
固态的水是水、液态的水也是水、气态的水也是水
水果:
波罗蜜、香蕉、榴莲
波罗蜜是水果、香蕉是水果、榴莲是水果
水果是波罗蜜,这么说是不可以的。
动物:
狗、虎、猫、大象
狗是动物,这么说是没问题的
动物是狗,这么说是不可以的。
多态的前提
1、要有继承关系
2、要有方法的重写。
其实没有重写也是可以的,但是不重写就没有意义
动物都有吃这个方法,但是每个具体的动物吃的实现不一样,变现出不同动物的特有属性
3、要有父类的引用指向子类对象
格式
父类名 f = new 子类名(…);
多态访问成员的特点
1、成员变量
编译看左,运行看左
2、构造方法(初始化作用)
创建子类对象的时候,先访问父类中的构造方法,对父类的数据先进行初始化
3、成员方法
编译看左,运行看右。
因为成员方法存在重写,所以访问看右边
4、静态成员方法
编译看左,运行也看左。
(由于被static修饰的成员都是与类相关的,这里不是重写,所以运行的时候,访问的还是左边的)
代码示例:
package com.shujia.wyh.day11;
class Fu3{
int num = 100;
public void show(){
System.out.println("这是父类中show()方法");
}
public static void fun(){
System.out.println("这是父类中的静态fun方法");
}
}
class Zi3 extends Fu3{
int num = 1000;
@Override
public void show(){
System.out.println("这是子类中的show()方法");
}
public void show2(){
System.out.println("这是子类特有的方法1");
}
public static void fun(){
System.out.println("这是子类中的静态fun方法");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建了一个对象
Fu3 f = new Zi3();//父类指向子类对象
System.out.println(f.num);//100
f.show(); // 这是子类中的show()方法
f.fun();//这是父类中的静态fun方法
}
}
多态的好处
1、多态可以使代码的扩展性很好(这是由继承所保证的)
2、多态可以使代码的维护性很好(这是由多态保证的)
代码示例:
package com.shujia.rx.day12;
class Animal{
String name;
int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void sleep(){
System.out.println("睡觉");
}
public void eat(){
System.out.println("吃");
}
}
class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void sleep() {
System.out.println("狗侧着睡");
}
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void sleep() {
System.out.println("猫趴着睡");
}
@Override
public void eat() {
System.out.println("🐱吃鱼");
}
}
//用工具类改进
class AnimalTool{
public static void useAnimal(Animal animal){ //Animal animal=new Cat("小白",9);
//利用了多态访问成员方法的特点,编译看左,运行看右,实际调用的是子类对象中的方法。
animal.sleep();
animal.eat();
}
}
public class CatDogDemo {
public static void main(String[] args) {
//养一只狗
Dog d1 = new Dog("小黄",7);
d1.sleep();
d1.eat();
useDog(d1);
//养一只猫
Cat c1 = new Cat("小白",9);
c1.sleep();
c1.eat();
AnimalTool.useAnimal(c1);
}
//用方法改进
public static void useDog(Dog dog){
dog.sleep();
dog.eat();
}
}
多态的弊端
多态无法访问父类中方法名一样的方法
如果我想使用子类中的特有方法,还必须使用多态,怎么办呢?
1)就不使用多态,创建子类对象然后调用方法,但是再次创建对象,还会在堆内存中开辟空间,很有可能会造成资源浪费。
2)java考虑到这样的问题,提供了一个技术给我们使用:向下转型
向下转型
将父类的引用强制转换成子类的引用
格式:
子类类名 变量名 = (子类类名)父类的引用;
注意:
要求转型的类与父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类。
代码示例:
向下转型猫狗案例
class Animal2{
public void eat(){
System.out.println("吃");
}
}
class Dog2 extends Animal2{
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void lookDoor(){
System.out.println("看门");
}
}
class Cat2 extends Animal2{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫捉老鼠");
}
}
public class PolymorphicDemo4 {
public static void main(String[] args) {
//以多态的形式创建一个对象
Animal2 a = new Dog2();
a.eat();
// a.lookDoor();
//向下转型访问子类中特有的方法
Dog2 d = (Dog2) a;
d.eat();
d.lookDoor();
//ClassCastException类转换异常
Cat2 c = (Cat2) a; // 此刻内存中还是一个Dog2的对象,内存图解如下:
c.catchMouse();
}
}
代码示例:
不同地方饮食文化不同的案例
package com.shujia.wyh.day11;
/*
不同地方饮食文化不同的案例
Person
eat()
SouthPerson
eat()
NorthPerson
eat()
*/
class Person{
public void eat(){
System.out.println("吃");
}
}
class SouthPerson extends Person{
@Override
public void eat() {
System.out.println("南方人吃米饭");
}
public void playMaJiang(){
System.out.println("南方人打麻将");
}
}
class NorthPerson extends Person{
@Override
public void eat() {
System.out.println("北方人吃面食");
}
public void bath(){
System.out.println("北方人搓澡");
}
}
public class PolymorphicDemo5 {
public static void main(String[] args) {
//多态创建南方人对象
Person p = new SouthPerson();
p.eat();
// p.playMaJiang();
//向下转型
SouthPerson sp = (SouthPerson) p;
sp.eat();
sp.playMaJiang();
//多态创建北方人对象
Person p2 = new NorthPerson();
p2.eat();
// p2.bath();
//向下转型
NorthPerson np = (NorthPerson) p2;
np.eat();
np.bath();
}
}