第三章 3.9 多态及其常见错误

基础知识点

Java程序包括两个重要的阶段:
   第一阶段:编译阶段
            Animal a2 = new Cat();
            a2.move();
            在编译的时候,编译器只知道a2的类型是Animal类型。
            因此在编译的时候就会去Animal类中找move()方法。
            找到之后,绑定上去,此时发生静态绑定。能够绑定成功
            表示编译通过。

            new Cat()只能发生在运行期间开始执行,发生在堆当中开辟空间。
   第二阶段:运行阶段
           在运行的时候,堆内存中真实的java对象是Cat类型。
           所以move()的行为一定是Cat对象发生的。
           因此运行的时候就会调用Cat对象的move()方法。
           这种绑定称为运行期绑定/动态绑定。
  因为编译阶段是一种形态,运行的时候是另一种形态。因此得名:多态。

多态语法:向上/向下类型转换

关于基本数据类型之间的类型转换:
  第一类:小容量转换成大容量,叫做自动类型转换;
      int i = 100;
      long x = i;
  第二类:大容量转换成小容量,必须添加强制类型转换符才行。叫做强制类型转换。
      int y = (int)x;

 除了基本数据类型之间的类型转换之外,对于引用数据类型来说,也可以进行类型转换。只不过不叫做自动或者强制类型转换。叫做向下或向上类型转换。

 关于java语言中的向上转型和向下转型:
          向上转型(upcasting):子 ---> 父 (可以等同看作自动类型转换)
          向下转型(downcasting):父 ---> 子 (可以等同看作强制类型转换)
 不管是向上还是向下转型,两种类型之间必须要有继承关系,编译器才能编译通过,这个最基本的前提。

代码实例:

public class Animal {
    public void move(){
        System.out.println("动物在移动");
    }
    public void eat(){
        System.out.println("正在吃东西");
    }
}

public class Cat extends Animal {

    @Override
    public void move() {
        System.out.println("猫在走猫步");
    }
    /*

        这个方法/行为是子类特有的,父类没有
     */
    public void catchmouse(){
        System.out.println("猫在抓老鼠");
    }
}
public class Bird extends Animal {
    @Override
    public void move() {
        System.out.println("鸟儿在飞翔");;
    }
}

代码里的注释非常重要!!! 

涉及到向上/向下类型转换的基本原理和基本常见错误及其解决办法。

/**
 * 关于基本数据类型之间的类型转换:
 *  第一类:小容量转换成大容量,叫做自动类型转换;
 *      int i = 100;
 *      long x = i;
 *  第二类:大容量转换成小容量,必须添加强制类型转换符才行。叫做强制类型转换。
 *      int y = (int)x;
 *
 * 除了基本数据类型之间的类型转换之外,对于引用数据类型来说,也可以进行类型转换。只不过不叫做自动或者强制类型转换。叫做向下或向上类型转换。
 *
 * 关于java语言中的向上转型和向下转型:
 *          向上转型(upcasting):子 ---> 父 (可以等同看作自动类型转换)
 *          向下转型(downcasting):父 ---> 子 (可以等同看作强制类型转换)
 * 不管是向上还是向下转型,两种类型之间必须要有继承关系,编译器才能编译通过,这个最基本的前提。

 **/
public class Test01 {
    public static void main(String[] args) {
        //创建对象
        Animal a1 = new Animal();
        a1.eat();
        a1.move();

        Cat c1 = new Cat();
        c1.move();
        c1.eat();

        Bird b1 = new Bird();
        b1.move();
        b1.eat();
    /*-------------------------------多态基本原理讲解-----------------------------------*/
        /*
            父类型更宽泛,子类型更精确
        * 向上转型(upcasting):
        *   1.子---> 父
        *   2.也可以等同看作自动类型转换
        *   3.前提:两种类型之间要有继承关系
            4.父类型引用指向子类型对象。这个就是多态机制最核心的语法。
            Animal a2 = new Cat();
        * */

        Animal a2 = new Cat();

        /*
         Java程序包括两个重要的阶段:
            第一阶段:编译阶段
                     Animal a2 = new Cat();
                     a2.move();
                     在编译的时候,编译器只知道a2的类型是Animal类型。
                     因此在编译的时候就会去Animal类中找move()方法。
                     找到之后,绑定上去,此时发生静态绑定。能够绑定成功
                     表示编译通过。

                     new Cat()只能发生在运行期间开始执行,发生在堆当中开辟空间。
            第二阶段:运行阶段
                    在运行的时候,堆内存中真实的java对象是Cat类型。
                    所以move()的行为一定是Cat对象发生的。
                    因此运行的时候就会调用Cat对象的move()方法。
                    这种绑定称为运行期绑定/动态绑定。
           因为编译阶段是一种形态,运行的时候是另一种形态。因此得名:多态。
         */
        a2.move();

        /*以下代码是编译错误
            会报错,因为在编译阶段编译器只知道a2得类型是Animal类型,父类型中没有catchmouse()这个方法
            a2.catchmouse();
         */
        /*
           假如现在就是要让a2去抓老鼠怎么办?
                向下转型:downcasting(父--->子)
           什么时候我们会考虑使用向下转型?
                当调用的方法是子类中特有的方法。
         */
        Cat c2 = (Cat)a2;
        c2.catchmouse();

        /*
         发生编译错误,在多态中,大前提是有继承关系,Bird和Cat没有直接得继承关系。
         没有继承关系,编译器报错。
         Bird b2 = new Bird();
            Cat c3 =(Cat)b2;
         */

        //向下转型
        //为什么编译的时候可以通过?因为x是Animal类型,Animal和Bird之间存在继承关系,语法没问题,所以编译通过了。
        //为什么运行的时候出现ClassCastException异常?因为运行时堆中真实对象是Cat对象,Cat无法转换成Bird,则出现类型转换异常
        /*
        Bird y = (Bird)x;
         */
        Animal x = new Cat();
        // 做向下转型之前,为了避免ClassCastException得发生,一般建议使用instanceof进行判断
        /*
            instanceof 运算符的语法规则:
                1.instanceof运算符的结果一定是:true/false
                2. 语法格式:
                    (引用 instanceof 类型)
                3.例如:
                    (a instanceof Cat)
                    true表示什么?
                    引用指向的对象是Cat类型.
                    false表示什么?
         */
        if(x instanceof Bird){
            System.out.println("======");
            Bird y = (Bird)x;
        }


    }
}

软件开发七大原则

开闭原则

最基本原则

多态符合开闭原则

无多态机制

如果主人要养狗,不想养猫了,创建一个狗的类,但是Master主人类中的feed()方法是喂猫,要是想养狗还得改动此方法,这样就动了源代码。

不符合0CP。不符合开闭原则.(因为这个功能的扩展是建立在修改Master类的基础之上的。)

OCP倡导的是什么?进行功能扩展的时候,最好不要修改有代码,最好是以新增代码来完成扩展对修改关闭、刘扩展开放。

Cat类

主人类

主程序入口

多态机制

在无多态机制中,如果主人要想养其他宠物,我们除了新建一个其他的宠物类,还得修改主人类中的feed(要养的宠物)喂养的代码。

但是有了多态,我们可以解除Master类和不同宠物之间的联系。

//宠物类
public class Pet{

        public void eat(){}

}

//猫类

public class Cat extends Pet{   
    @Override
    public void eat(){
        Sysyem.out.println("猫吃鱼");
   
}

//狗类
public class Dog extends Pet{   
    @Override
    public void eat(){
        Sysyem.out.println("狗吃骨头");
   
}

//主人类

public class Master{
    public void feed(Pet p){
        p.eat();
    }
}


//main
public static void main(String[] args){
Cat c = new Cat();
Dog d = new Dog();
Master lisi = new Master();

//喂养
lisi.feed(c);
lisi.feed(d);
}

假如主人又想养兔子了,我们用多态机制,则不需要动Master中的源码,只需要增加一个新的兔子类即可。

public class Rabbit{
    @Override
    public void eat(){
        Sysyem.out.println("兔子吃胡萝卜");
   

}
//main
public static void main(String[] args){
Cat c = new Cat();
Dog d = new Dog();
Rabbit r = new Rabbit();
Master lisi = new Master();

//喂养
lisi.feed(c);
lisi.feed(d);
lisi.feed(r);
}

静态方法与方法覆盖

都知道,java的三大特性,封装、继承、多态。继承中有方法覆盖,方法有静态方法与动态方法。

但是方法覆盖针对的是实例方法,和静态方法无关。(方法覆盖和多态机制联合起来才有意义。)

public class Animal {
    public static void test(){
     System.out.println("Animal执行了");
}

}

public class Cat extends Animal {

    
    public static void test() {
        System.out.println("Cat执行了");
    }

public calss Test{
    public static void main(String[] args){
    //结果分别执行每个类里边的test方法
    Animal.test();
    Cat.test();

    Animal a = new Cat();
    a.test(); //执行结果是“Animal执行了”。
    //原因:静态方法在内存中单独开辟空间,不与对象绑定,与类绑定。a对应的是Animal类,所以直接调用的是Animal中的test方法。与多态无关。

}

}

实例变量与多态无关

实例变量没有多态这一说,与多态无关。记住就行,不需要弄懂原理。

下例代码结果为 “张三”。

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值