多态

面向对象的三大特征:
        1. 封装
        2. 继承
        3. 多态
多态:

什么叫多态:一个对象具备多种形态,也可以理解为事物存在的多种体现形态(父类的引用类型变量指向了子类对象,或者是接口的引用类型变量指向了接口实现类的对象)

多态的前提:必须存在继承或者实现关系。
多态要注意的细节:
1. 多态情况下,子父类存在同名的成员变量时,访问的是父类成员变量
2. 多态情况下,子父类存在同名的非静态的成员函数时,访问的是子类成员函数
3. 多态情况下,子父类存在同名的静态的成员函数时,访问的是父类成员函数
4. 多态情况下,不能访问子类特有的成员
总结:多态情况下,子父类存在同名的成员时,访问的都是父类成员,除了在同名非静态函数时才是访问子类的。

abstract class Animal{
    String name;
     static String color="动物色";
    public Animal(String name){
        this.name=name;
    }
    public abstract void run();
    public  void eat(){
        System.out.println("动物在吃东西");
    }
}

//老鼠
class Mouse extends Animal{
    static String color="老鼠色";
    public Mouse(String name){
        super(name);
    }
    public void run(){
        System.out.println(name+"四条腿,灵活的走位");
    }
    public  void eat(){
        System.out.println("老鼠在吃东西");
    }
    public void dig(){//老鼠特有的方法
        System.out.println("老鼠在打洞");
    }
}

class Fish extends Animal{
    public Fish(String name){
        super(name);
    }
    public void run(){
        System.out.println(name+"在海中快速的游行");
    }
}

public class Demo4 {//多态

    public static void main(String[] args) {
        Animal a=new Mouse("老鼠" );
        System.out.println(a.color);
        a.eat();
    }
}
编译看左边,运行不一定看右边
编译看左边:java编译器在编译的时候,会检查引用类型变量所属的类是否具备指定的成员,如果不具备,马上编译报错。
普通的情况都是看左边,只有非静态函数的时候才是看右边的

凡是引用类型变量,都是记录了一个内存地址而已,指向那边。


多态的应用场景:
        1. 多态用于形式参数类型的时候,可以接受更多类型的数据 。
        2. 多态用于返回值类型的时候,可以返回更多类型的数据。

多态的好处:提高了代码的拓展性。

需求1:
定义一个函数,可以接受任意类型的图形对象,并且打印图形面积与周长

abstract class MyShape{
    public abstract void getArea();
    public abstract void getLength();
}

class Circle extends MyShape{
    public static final double PI=3.14;
    double r;
    public Circle(double r){
        this.r=r;
    }
    public void getArea(){
        System.out.println("圆形的面积"+PI*r*r);
    }
    public  void getLength(){
        System.out.println("圆的周长"+2*PI*r);
    }

}

class Rect extends MyShape{
    int width;
    int height;
    public Rect(int width,int height){
        this.width=width;
        this.height=height;
    }
    public void getArea(){
        System.out.println("矩形的面积是"+width*height);
    }
    public void  getLength(){
        System.out.println("矩形的周长是"+(width+height)*2);
    }

}
public class Demo5 {
    public static void main(String[] args) {
       Circle c=new Circle(2.0);
       print(c);
 }
public static void print(MyShape s){    //MyShape s=new Circle(4.0);
        s.getArea();
        s.getLength();
    }
}

需求2:定义一个函数可以返回任意类型的图形对象。

public class Demo5 {
    public static void main(String[] args) {
       MyShape m=getShape(0);//调用了使用多态,定义的变量类型要以返回值类型一致。
        m.getArea();
        m.getLength();
 }
public static MyShape getShape(int i){
        if(i==0){
            return new Circle(4.0);
        }
        else{
            return new Rect(3,4);
        }
    }
    }

需求3:

创建三个类,三个类分别是Pet,Cat,TestPetCat,父类为Pet,定义name,age属性并封装取来,Cat继承Pet,然添加一个color属性,在主函数TestPetCat输出。(利用多态)

public class Pet {
    private String name;
    private int age;

    public Pet(){
        super();
    }
    public Pet(String name,int age){
        super();
        setName(name);
        setAge(age);
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 0 && age < 10) {
            this.age = age;
        } else {
            System.out.println("年龄不合法");
        }
    }
    public void show(){
        System.out.println("名字:"+getName()+",年龄:"+getAge());
    }
}

public class Cat extends Pet{
    private String color;

      public Cat(){
          super();
      }
      public Cat(String name,int age,String color){
          super(name,age);
          setColor(color);
      }
    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public void show(){
        System.out.println("花色:"+getColor());
    }
}

 public static void main(String[] args) {
        //使用父类类型的引用指向父类自己的对象,没有多态
        Pet p1=new Pet();
         //无论是否重写show()方法,都调用Pet类中的show方法
        p1.show();
        System.out.println("----------------------");
        //使用子类类型的引用指向父类自己的对象,没有多态
        //当子类重写show()方法后,则调用子类中重写以后的方法
        Cat c1=new Cat("小花",2,"白色");
        //调用Pet类中的show()方法
        c1.show();
        System.out.println("----------------------");
        //父类类型的引用指向了子类的对象,形成了多态
        Pet pc=new Cat("喵咪",3,"咖啡色");
        //调用Pet类的show方法
        //当子类重写show()方法后,在运行阶段最终调用了子
        类重写以后
        的版本
        //在编译阶段还是调用父类的方法,运行阶段调子类
        pc.show();
    }

Pet pc=new Cat();
pc.show();
解析:
对于上述代码来说,采用父类的引用指向子类的对象后:在编译阶段 pc还是父类类型的,因此只可以调用父类的show()方法:在运行阶段pc是子类类型的,因此最终调用了子类重写以后的show()方法。


多态的效果:
             1.当父类的引用指向子类的对象时,该引用可以直接调用父类的成员方法,但是不可以直接
              调用子类的成员变量
             2.对于父子类都拥有的非静态成员方法来说,编译阶段调用父类的,
             运行阶段调用子类的
             3.对于父子类都拥有的静态成员方法来说,编译和运行阶段调用父类的版本,与对象无关。

引用数据类型之间的转换

1.引用数据类型之间的转换分为俩种,自动类转换和强制类型转换;

  1. 自动类型转换主要指从小范围到大范围之间的转换,也就是子类向父类的转换。(Pet pc=new Cat() 这是自动类型转换)
  2. ((Cat)pc).getColor();父类到子类的转换,强制类型转换主要指从大范围到小范围之间的转换,也就是父类向子类的转换。

2.引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
3.拥有父子类关系后可以发生强制类型转换,若该引用真正指向的对象并不是目标类型的对象时,编译阶段ok,运行阶段发生类型转换异常。

4.为了避免上述错误的发生,每次强转之前,应该使用instanceof进行判断,格式如下:
if(引用变量名 instanceof 目标类型)— 判断引用变量指向的对象是否为目标类型

如果用多态,就是父类的引用指向子类,而父类的引用能直接访问父类的方法,若想访问子类的,需要加个强转


在这里插入图片描述

多态的实际意义:
多态的实际意义在于屏蔽不同子类的差异性实现通用的编程

public class TestShape  {
    //自定义成员方法实现将参数指定矩形对象的特征打印出来
    //Recr rt=new Rect(1,2,3,4);
    //矩形类型的引用指向矩形类型的对象,没有多态
    //矩形类型的引用指向矩形类型的对象,没有多态
    public static void drowRect(Rect rt){
        //调用矩形类中的show方法

        rt.show();
    }
    //圆形类型的引用指向圆形类型的对象,没有多态
    public static void drowCircle(Circle ce){
        ce.show();
    }
    //可能一会传圆形一会传矩形
    //父类类型的引用指向了子类的对象,形成了多态
    public static void draw(Shape s){
        //编译阶段调用父类的方法,运行阶段调用子类重写以后的方法
        //Shape s=new Rect(1,2,3,4)
        //Shape s=new Circle(4,4,6)
         s.show();
    }
    public static void main(String[] args){
           TestShape.drowRect(new Rect(1,2,3,4));//Rect rt = new rect(1,2,3,4);
               System.out.println("---------------");
           TestShape.drowCircle(new Circle(5,6,2.0));
        System.out.println("---------------");

           TestShape.draw(new Rect(1,2,3,4));
          System.out.println("---------------");
          TestShape.draw(new Circle(4,4,6));//shape s = new circle();

          }
          }

主板运行网卡声卡的案例:

interface PCI{
    public void open();
    public void close();
}

class MainBpard {
    public void run(){
        System.out.println("主板运行成功-------");
    }
    public void userPCI(PCI p){
        if (p!=null){
            p.open();
            p.close();
        }
    }
}

class NetCard implements PCI{
    public void open(){
        System.out.println("netcard open");
    }
    public void close(){
        System.out.println("nedcard close");
    }
}

class SoundCard implements PCI{
    public void open(){
        System.out.println("SoundCard open");
    }
    public void close(){
        System.out.println("SoundCard close");
    }
}
public class Demo {
    public static void main(String[] args) {
        MainBpard m=new MainBpard();
        m.run();
        m.userPCI(new NetCard());
        m.userPCI(new SoundCard());
    }
}

在这里插入图片描述

  • 29
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值