CGB2105--Day08--笔记

1 多态

1.1 概述

在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。 多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。
多态是面向对象程序设计(OOP)的一个重要特征,指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。

1.2 特点

  1. 多态的前提1:是继承
  2. 多态的前提2:要有方法的重写
  3. 父类引用指向子类对象,如:Animal a = new Cat();
  4. 多态中,编译看左边,运行看右边
    在这里插入图片描述

1.2.1 多态入门案例

public class TestDemo {
    public static void main(String[] args) {
        Animal a = new Animal();
        Cat c = new Cat();
        Dog d = new Dog();
        a.eat();
        c.eat();
        d.eat();
        /** 2、父类不能调用子类的特有功能 */
        //a.play();
        c.play();
        d.play();

        /** 3、口诀:格式:父类引用指向子类对象
         * 解释:创建出来的子类对象地址值交给父类类型的引用类型变量来保存
         */
        Animal a2 = new Cat();
        Animal a3 = new Dog();
        /**
         * 4、口诀:编译看左边运行看右边
         * 解释:必须要父类定义这个方法,才能通过编译,编译时,把多态对象看做是父类类型
         *      必须要子类重写这个方法,才能满足多态,运行时实际干活的是子类
         */
        a2.eat();
        //a2.play();// 多态对象把自己看做父类类型,不能使用子类的特有方法
    }
}

/**
 * 1、多态的前提:继承 + 重写
 */
class Animal {
    public void eat() {
        System.out.println("小动物Animal吃啥都行~");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("小猫爱吃小鱼干~");
    }

    public void play() {
        System.out.println("小猫Cat跳得老高啦~");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("小狗爱吃肉骨头~");
    }

    public void play() {
        System.out.println("小狗Dog跑得老快啦~");
    }
}

1.3 多态的好处

  1. 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
  2. 提高了程序的可扩展性和可维护性

1.3.1 多态的使用

前提:多态对象把自己看做是父类类型

  1. 成员变量: 使用的是父类的
  2. 成员方法: 由于存在重写现象,所以使用的是子类的
  3. 静态成员: 随着类的加载而加载,谁调用就返回谁的

1.3.2 案例练习1

public class TestDemo2 {
    public static void main(String[] args) {
        Animal2 a = new Animal2();
        Dog2 d = new Dog2();
        /**
         * 口诀:父类引用指向子类对象
         */
        Animal2 a2 = new Dog2();
        d.eat();
        d.play();
        /**
         * 口诀2:编译看左边,运行看右边
         * 2、多态中成员变量使用的都是父类的
         */
        System.out.println(a2.sum);
        /**
         * 3、多态中,成员方法的定义使用的是父类的,实现(方法体)使用的是子类的
         */
        a2.eat();
        /**
         * 4、多态中,如果父子类都有静态重名的方法,这个不是重写的现象,所以静态方法调用的还是父类的实现(方法体)
         */
        a2.play();
    }
}

class Animal2 {
    int sum = 10;
    public void eat() {
        System.out.println("吃啥都行");
    }

    public static void play() {
        System.out.println("玩啥都行");
    }
}

/**
 * 1、多态前提:继承 + 重写
 */
class Dog2 extends Animal2 {
    int sum = 20;
    @Override
    public void eat() {
        System.out.println("小狗爱吃肉包子!");
    }

    /**
     * 3、静态方法不存在重写的现象,在哪个类里写,就属于哪个类的资源,可以被类名直接调用
     */
    public static void play() {
        System.out.println("小狗爱打滚儿~");
    }
}

1.3.3 案例练习2

public class TestExec {
    public static void main(String[] args) {
        Car c = new Car();
        System.out.println(c.getColor());
        c.start();
        c.stop();

        BMW b = new BMW();
        System.out.println(b.color);
        b.start();
        b.stop();

        Car c2 = new BMW();
        /**
         * 多态对象调用方法,如果方法没有重写,使用的是父类的功能,因为他把自己看做父类型
         * 如果方法重写了,那么方法的定义看父类,方法体看子类
         */
        c2.start();
        c2.stop();
    }
}

class Car {
    private String brand;
    private String color;
    private double price;
    private double size;

    public void start() {
        System.out.println("启动我心爱的小车车~");
    }

    public void stop() {
        System.out.println("赶紧刹车~");
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public double getSize() {
        return size;
    }

    public void setSize(double size) {
        this.size = size;
    }
}

class BMW extends Car {
    String color = "五彩斑斓的黑";

    @Override
    public void start() {
        System.out.println("咻咻咻~发射成功");
    }
}

class TSL extends Car {
    String color = "黑不溜秋的白";

    public void fly() {
        System.out.println("哎呀!我的小车车飞起来啦了~");
    }
}    

2 异常

2.1 概述

Java Exception 异常处理机制其实起源很早,所以它也不是个什么新鲜的东西,如果您对Exception机制一点都不了解,没关系,只是国内通常接触新事物的时间都相对的要晚老美几年,但了解Java Exception机制对Java开发人员来说是必要的,不过Exception 异常处理机制也并没有固定,在Anders 的眼里它也是一个试验性的东西。 理论上异常处理划分为两个模型(中止模型与继续模型),但实际使用方面我们对中止模型用的比较多,这个模型比较实用,而继续模型则不是那么的应用普遍,多少是耦合的过于紧密。

异常是一些用来封装错误信息的对象
它由异常的类型、提示信息、报错的行号提示三部分组成

2.2 异常的继承结构

在这里插入图片描述

2.3 异常的处理方式

当程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出
当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常
大家可以结合生活中的例子:如果工作中遇到了问题,我们可以选择自己处理(捕获),或者交给上级处理(抛出)

  1. 捕获方式
    在这里插入图片描述
  2. 抛出方式
    对于不想现在处理或者处理不了的异常可以选择向上抛出
    方式:在方法上设置异常的抛出管道,即:
    在可能会会发生异常的方法上添加代码:
    throws 异常类型

2.3.1 异常案例练习

public class ExceptionDemo2 {
    //public static void main(String[] args) throws Exception {//因为没人解决了,不推荐
    public static void main(String[] args)  {
        //method1();//测试暴露异常
        //method2();//测试异常解决方案一
        f3();//在method3()被调用之前处理它的异常
        //method3();//测试异常解决方案二
    }

    private static void f3() {//本方法用于解决method3()抛出的异常
        try{
            method3();//业务是f3处理调用method3()时抛出的异常
        }catch (Exception e){
            System.out.println("请输入正确的数据!");
        }
    }

    /*如果一个方法抛出了异常,那么谁调用这个抛出异常的方法,谁就需要处理这个异常
     * 这里的处理也有两种解决方案:捕获自己解决/继续向上抛出
     * 但是注意:我们一般会在main()调用之前处理掉异常
     * 而不是把问题直接抛给main(),因为没人解决了*/
    /*异常处理方案二:异常抛出--自己不处理,交给别人处理
     * 异常抛出的格式:在方法定义的小括号与大括号之间写:throws 异常类型
     * 如果有多个异常,可以使用逗号进行分隔*/
    private static void method3()
            throws InputMismatchException,ArithmeticException,Exception{
        //1.复写刚刚的业务代码
        System.out.println("请您输入要计算的第一个数:");
        int a = new Scanner(System.in).nextInt();
        System.out.println("请您输入要计算的第二个数:");
        int b = new Scanner(System.in).nextInt();
        System.out.println(a/b);
    }
    /*异常处理方案一:异常捕获--自己处理
    try{
       可能会出现异常的代码
    }catch(要匹配的异常类型 异常名){
       匹配到异常提供的解决方案
    }
    * */
    private static void method2() {
        try{
            //1.复写刚刚的业务代码
            System.out.println("请您输入要计算的第一个数:");
            int a = new Scanner(System.in).nextInt();
            System.out.println("请您输入要计算的第二个数:");
            int b = new Scanner(System.in).nextInt();
            System.out.println(a/b);
        }catch(InputMismatchException e){//注意导包
            System.out.println("请输入正确的数据类型!");
            e.printStackTrace();//打印错误信息到控制台
        }catch(ArithmeticException e){
            System.out.println("除数不能为0!");
        }catch(Exception e){/*提供的是通用解决方案,多态最为经典的一种实现*/
            System.out.println("输入的数据不正确!请重新输入!");
        }
        /*关于多态,我们并不关心子类具体的异常类型
         * 而是统一将所有的异常类型看作是父类类型来处理
         * 提供的是通用的解决方案
         * 所以异常处理可以嵌套,也可以不嵌套,只提供一种通用解决方案*/
        /*注意:运行时异常可以不做编码处理,只不过有时运行时会报错
         * Java是不强制要求代码做运行时异常的处理的,只不过处理后程序更加完美健壮*/
    }

    private static void method1() {
        //1.提示并接收用户输入的两个整数
        System.out.println("请您输入要计算的第一个数:");
        int a = new Scanner(System.in).nextInt();
        System.out.println("请您输入要计算的第二个数:");
        int b = new Scanner(System.in).nextInt();
        //2.打印接收到两个整数的除法结果
        System.out.println(a/b);
        //输入任意一个小数:InputMismatchException--输入不匹配异常
        //除数为0:ArithmeticException--算数异常
        /*1.不要害怕BUG,真正的勇士敢于直面自己写的BUG*/
        /*2.学会看报错的信息提示,确定自己错误的方向*/
        /*3.学会看报错的行号信息,确定自己报错的位置,哪里不对点哪里
         * 注意!!!源码不会错,要看自己写的代码*/
    }
}

2.4 catch 和 throws

异常处理只有两种方式: catch 和 throws,所以必须二选一
由于Java语法本身的特点,需要开发者事先考虑异常如何处理,也就是我们常说的:“未雨绸缪”
对于初级开发者来说,我们可能会捕获,但不处理异常
try {

} catch(Exception e) {
}
底层异常,应该向前抛到前面处理
经验少时,不知道该在什么位置捕获处理,应该选择 throws
但是大家需要注意,在异常抛出时,有些异常比如运行时异常,可能并不会强制要求抛出此异常,调用时也没有报错显示需要额外处理,这个时候就需要大家平时多积累,掌握良好的编码习惯了,手动添加代码进行预处理,增强程序的健壮性了。

2.5 异常类型

程序错误分为三种:
编译错误(checked异常);
运行时错误(unchecked异常);
逻辑错误;

  1. 编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置,这个也是大家在刚接触编程语言最常遇到的问题。
  2. 运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。
  3. 逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。

2.6 throws 与 throw 的区别

  1. throws
    用在方法声明处,其后跟着的是异常类的名字
    表示此方法会抛出异常,需要由本方法的调用者来处理这些异常
    但是注意:这只是一种可能性,异常不一定会发生
  2. throw
    用在方法的内部,其后跟着的是异常对象的名字
    表示此处抛出异常,由方法体内的语句处理
    注意:执行throw一定抛出了某种异常

3 抽象类

3.1 概述

Java中可以定义被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法.
Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类

  1. 如果一个类含有抽象方法,那么它一定是抽象类
  2. 抽象类中的方法实现交给子类来完成

3.2 抽象方法格式

在这里插入图片描述

3.3 特点

  1. abstract 可以修饰方法或者类
  2. 被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法
  3. 抽象类中可以没有抽象方法
  4. 如果类中有抽象方法,那么该类必须定义为一个抽象类
  5. 子类继承了抽象类以后,要么还是一个抽象类,要么就把父类的所有抽象方法都重写
  6. 多用于多态中
  7. 抽象类不可以被实例化

3.3.1 抽象类入门案例

public class AbstractDemo {
    public static void main(String[] args) {
        /**
         * 3、抽象类不可实例化--创建对象
         */
        //new Phone();
        Phone p = new XM();
        p.call();
        p.message();
        p.money1();
        p.money2();
    }
}

/**
 * 1、被abstract修饰的类时抽象类
 * 如果一个类中包含了一个抽象方法,那么这个类必须被声明一个抽象类
 */
abstract class Phone {
    public void call() {
        System.out.println("正在打电话~");
    }

    public void message() {
        System.out.println("正在发短信~");
    }

    public void message2() {
        System.out.println("正在发短信~");
    }

    /**
     * 2、被abstract修饰的方法是抽象方法,抽象方法没有方法体
     */
    abstract public void money1();
    abstract public void money2();
}

/**
 * 4、当一个类继承了一个抽象父类,有两种解决方案:
 * 方案一:变成一个抽象子类
 * 方案二:变成抽象子类,实现抽象父类中的所有抽象方法
 */
class XM extends Phone {

    @Override
    public void money1() {
        System.out.println("实现父类未实现的方法");
    }

    @Override
    public void money2() {
        System.out.println("实现父类未实现的方法2");
    }
}

3.3.2 总结

abstract注意事项:
抽象方法要求子类继承后必须重写。
那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。

  1. private:被私有化后,子类无法重写,与abstract相违背。
  2. static:静态优先于对象存在,存在加载顺序问题。
  3. final:被final修饰后,无法重写,与abstract相违背。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

直男编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值