zoukankan      html  css  js  c++  java
  • day1020211212

    湖南Java

    面向对象04 异常 异常解决方案 抽象类 面向抽象编程

    1.异常

    1.1概念

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

    1.2异常的继承结构

    1.3异常的处理方式

    当程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出
    当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常
    捕获方式:

    抛出方式:
    对于不想现在处理或者处理不了的异常可以选择向上抛出
    方式:在方法上设置异常的抛出管道,即:
    在可能会发生异常的方法上添加代码:
    throws 异常类型
    例如:void method1 throws Exception1,Exception2,Exception3{}
    TIPS:方法上有默认的异常管道:RuntimeException

    private static void method3() throws ArithmeticException,InputMismatchException,Exception{ }

    private static void method3() throws Exception{ }

    • 如果一个方法抛出了异常,那么谁来调用这个方法,谁就需要处理这个异常,这里的处理也有两种方案:捕获解决 或者 继续向上抛出
    • 不能直接把异常抛给main(),因为调用main()是JVM,没人解决了,该报错还报错,所以我们一般会在main()调用之前将异常解决掉

    1.4练习:异常测试

    创建包:cn.tedu.oop
    创建类:ExceptionDemo.java

    package cn.tedu.oop;
    
    import java.util.InputMismatchException;
    import java.util.Scanner;
    
    /*本类用于异常的入门案例*/
    public class ExceptionDemo {
        //public static void main(String[] args) throws Exception {//问题实际未处理,还报错
        public static void main(String[] args) {
            //method1();//调用暴露异常的方法
            //method2();//调用解决异常的方法--异常解决方案1--捕获处理--自己解决
            /*main()不直接调用会抛出异常的method3()
            * 而是调用f(),f()解决了method3()可能会抛出的异常*/
            f();
            //method3();//调用解决异常的方法--异常解决方案2--向上抛出--交给调用者来解决
        }
        //相当于在main()调用method3()之前解决了method3()可能会抛出的异常
        private static void f() {
            try {
                method3();
            }catch (Exception e){
                System.out.println("您输入的数据不对~请重新输入!");
            }
        }
    
        /*如果一个方法抛出了异常,那么谁来调用这个方法,谁就需要处理这个异常
        * 这里的处理也有两种方案:捕获解决 或者 继续向上抛出
        * 但注意:我们一般会在main()调用之前将异常解决掉
        * 而不是将问题抛给main(),因为没人解决了,该报错还报错*/
        /*异常抛出的格式:在方法的小括号与大括号之间,写:throws 异常类型
        * 如果有多个异常,使用逗号分隔即可*/
        //0.定义一个解决异常的方法-方案2
        //private static void method3() throws ArithmeticException,InputMismatchException{
        private static void method3() throws 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(异常的类型 异常的名字){
        *    万一捕获到了异常,进行处理的解决方案
        * }
        * try-catch结构可以嵌套,如果有多种异常类型需要特殊处理的话
        * */
        //0.定义一个解决异常的方法-方案1
        private static void method2() {
            //1.按照捕获处理的格式完成结构
            try{
                //2.复写一下刚刚的代码
                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(ArithmeticException e){//异常类型 异常名
                System.out.println("除数不能为0!");
            }catch (InputMismatchException e){
                System.out.println("请输入规定的整数类型!");
            /*使用多态的思想,不论是什么子异常,统一看作父类型Exception
            * 做出更加通用的解决方案,甚至可以只写这一个,上面2个不写了*/
            }catch (Exception e){
                System.out.println("您输入的数据不对~请重新输入!");
            }
        }
    
        //0.定义一个用来暴露异常的方法
        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.输出两个数除法的结果
            //输入11和0,报错:ArithmeticException--算术异常,除数不能为0,数学规定
            //输入11和3.4,报错:InputMismatchException--输入不匹配异常
            System.out.println(a/b);
            /*1.不要害怕BUG,真正的勇士敢于直面自己写的BUG*/
            /*2.学会看报错的信息提示,确定自己错误的方法*/
            /*3.学会看报错的行号提示,确定自己报错的位置,哪里不对点哪里
            * 注意:源码不会错,要看的是自己写的代码*/
        }
    }
    

    1.5拓展1 catch和throws

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

    try {
    …
    } catch(Exception e) {
    }
    

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

    1.6拓展2

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

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

    其实我们还可以手动针对逻辑错误执行异常的抛出动作,大家可以理解成方法return,只不过此处我们返回的是异常,格式:
    if(逻辑错误有异常){
    AException e = new AException(“提示消息”);
    throw e;
    }

    package cn.tedu;
    
    import java.util.Scanner;
    
    public class TestThrow {
        public static void main(String[] args) {
            method4();
        }
    
        public static void method4(){
            //1.复写刚刚可能会发生异常的代码
            System.out.println("请输入您要计算的第一个数据:");
            int a = new Scanner(System.in).nextInt();
            System.out.println("请输入您要计算的第二个数据:");
            int b = new Scanner(System.in).nextInt();
            try{
                double result = divide(a,b);
                System.out.println(result);
                //System.out.println(a/b);
            }catch (ArithmeticException e){
                System.out.println("不能除0是我们的错,请鞭笞我们吧!");
            }
        }
    
        private static double divide(int a,int b) {
            if(b == 0){
                ArithmeticException e = new ArithmeticException("/ by zero");
                throw e;//类似于return e;
            }
            return a/b;
        }
    
    }
    

    1.7拓展3

    throws 与 throw 的区别
    throws
    用在方法声明处,其后跟着的是异常类的名字
    表示此方法会抛出异常,需要由本方法的调用者来处理这些异常
    但是注意:这只是一种可能性,异常不一定会发生

    throw
    用在方法的内部,其后跟着的是异常对象的名字
    表示此处抛出异常,由方法体内的语句处理
    注意:执行throw一定抛出了某种异常

    2.抽象

    2.1抽象类

    1. 被abstract修饰的方法是抽象方法,抽象方法没有方法体
    2. 一旦一个类有抽象方法,这个类必须被声明成抽象类
    3. 如果一个子类继承了一个抽象父类,有两种解决方案:
      1)抽象子类:不实现/实现一部分抽象父类中的抽象方法
      2)普通子类:实现抽象父类中全部的抽象方法
    4. 抽象类不能实例化
    5. 抽象类有构造函数的,但是,不是为了自己使用,而是为了子类super()调用
    6. 抽象类可以定义成员变量/成员常量
    7. 抽象类可以定义全普/全抽/半普半抽
    8. 如果一个类不想被外界实例化,可以把这个类声明成抽象类
    9. abstract关键字不可以与private static final共用

    2.2练习:抽象类入门案例

    创建包:cn.tedu.oop
    创建类:AbstracDemo.java

    package cn.tedu.oop;
    /*本类用作抽象测试的入门案例*/
    public class AbstractDemo {
        public static void main(String[] args) {
            /*4.抽象类不可以实例化!!!-创建对象*/
            //5.测试抽象父类是否可以创建对象
            //Animal a = new Animal();
            //6.创建多态对象进行测试
            Animal a = new Pig();
            a.eat();//调用抽象父类的普通方法
            a.fly();//调用抽象父类的抽象方法
    
        }
    }
    //1.创建父类Animal
    /*2.被abstract修饰的类是抽象类
    * 如果一个类中包含了抽象方法,那这个类必须被声明成一个抽象类*/
    //4.2添加抽象方法后,本类需要用abstract修饰
    abstract class Animal{
        //3.创建普通方法
        public void eat(){
            System.out.println("吃啥都行~");
        }
        public void play(){
            System.out.println("玩啥都行~");
        }
        //4.1创建抽象方法
        /*1.被abstract修饰的方法是抽象方法,抽象方法没有方法体*/
        public abstract void fly();
        public abstract void fly2();
    }
    //2.创建子类Pig,并与Animal类建立继承关系
    /*3.当一个子类继承了抽象父类以后,有两种解决方案:
    * 方案一:变成抽象子类,“躺平,我也不实现,继续抽象”
    * 方案二:实现抽象父类中的所有的抽象方法,“父债子偿”*/
    //4.3子类需要处理,继续抽象/实现父类所有抽象方法
    //abstract class Pig extends Animal{--方案一
    class Pig extends Animal{//方案二
        @Override//注解,标识这是一个重写的方法
        public void fly() {
            System.out.println("我爸的债我终于还清了,我家的猪终于飞起来了~");
        }
    
        @Override
        public void fly2() {
            System.out.println("抽象父类中的所有抽象方法都需要被实现");
        }
    }
    

    2.3练习:抽象类构造函数测试

    抽象类中的构造函数通常在子类对象实例化时使用
    创建包:cn.tedu.oop
    创建类:AbstractDemo2.java

    package cn.tedu.oop;
    /*本类用作抽象类构造函数测试*/
    /*抽象类是否有构造方法?有
    * 既然抽象类不能实例化,为什么要有构造方法呢?
    * 不是为了自己使用,而是为了子类创建对象时使用super(); */
    public class AbstractDemo2 {
        public static void main(String[] args) {
            //4.测试抽象类是否可以创建对象?不可以!!!
            //Animal2 a = new Animal2();
            //5.创建子类对象进行测试
            Pig2 p = new Pig2();
        }
    }
    //1.创建抽象父类Animal2
    abstract class Animal2{
        //3.创建构造方法
        public Animal2(){
            System.out.println("我是Animal2的构造方法~");
        }
    }
    //2.创建子类Pig2
    class Pig2 extends Animal2{
        //6.创建子类的无参构造
        public Pig2(){
            super();//表示调用父类的无参构造
            System.out.println("我是Pig2的构造方法~");
        }
    }
    

    2.4练习:抽象类成员测试

    创建包:cn.tedu.oop
    创建类:AbstractDemo3.java

    package cn.tedu.oop;
    /*本类用作抽象类中的成员测试*/
    public class AbstractDemo3 {
    }
    //1.创建抽象父类Fruit
    abstract class Fruit{
        /*1.抽象类中可以定义成员变量吗?--可以!!!*/
        //3.1定义抽象父类中的成员变量
        int sum = 100;
        /*2.抽象类中可以定义成员常量吗?--可以!!!*/
        //3.2定义抽象父类中的成员常量
        final String name = "XIAOHUANGREN";
        /*3.抽象类中可以定义普通方法吗?--可以!!!
        * 抽象类中可以都是普通方法吗?--也可以!!!*/
        /*4.如果一类中都是普通方法,那它为啥还要被修饰成抽象类呢?
        * 因为抽象类不可以被实例化,所以如果不想让外界创建本类的对象
        * 就可以把普通类声明成抽象类*/
        //4.定义抽象父类的普通方法
        public void clean(){
            System.out.println("水果还是要洗洗再吃哒~");
        }
        /*5.抽象类中可以定义抽象方法吗?--可以!!!*/
        /*6.如果类中添加了抽象方法,那么这个类必须被声明成抽象类*/
        //5.定义抽象父类中的抽象方法
        public abstract void grow();
        public abstract void clean2();
    }
    //2.创建子类Banana
    /*如果一个子类继承了抽象父类,有两种处理方案:
    * 方案一:继续抽象,也就是作为抽象子类,无需实现抽象方法-"躺平"
    * 方案二:不再抽象,实现继承自父类中的所有未实现的抽象方法-"父债子偿"*/
    class Banana extends Fruit{
        @Override
        public void grow() {
            System.out.println("一串香蕉老沉了~");
        }
        @Override
        public void clean2() {
            System.out.println("香蕉不用洗,香蕉喜欢被扒皮");
        }
    }
    

    2.5练习:抽象类成员测试

    创建包:cn.tedu.oop
    创建类:AbstractDemo3.java

    package cn.tedu.oop;
    /*本类用作抽象类中的成员测试*/
    public class AbstractDemo3 {
    }
    //1.创建抽象父类Fruit
    abstract class Fruit{
        /*1.抽象类中可以定义成员变量吗?--可以!!!*/
        //3.1定义抽象父类中的成员变量
        int sum = 100;
        /*2.抽象类中可以定义成员常量吗?--可以!!!*/
        //3.2定义抽象父类中的成员常量
        final String name = "XIAOHUANGREN";
        /*3.抽象类中可以定义普通方法吗?--可以!!!
        * 抽象类中可以都是普通方法吗?--也可以!!!*/
        /*4.如果一类中都是普通方法,那它为啥还要被修饰成抽象类呢?
        * 因为抽象类不可以被实例化,所以如果不想让外界创建本类的对象
        * 就可以把普通类声明成抽象类*/
        //4.定义抽象父类的普通方法
        public void clean(){
            System.out.println("水果还是要洗洗再吃哒~");
        }
        /*5.抽象类中可以定义抽象方法吗?--可以!!!*/
        /*6.如果类中添加了抽象方法,那么这个类必须被声明成抽象类*/
        //5.定义抽象父类中的抽象方法
        public abstract void grow();
        public abstract void clean2();
    }
    //2.创建子类Banana
    /*如果一个子类继承了抽象父类,有两种处理方案:
    * 方案一:继续抽象,也就是作为抽象子类,无需实现抽象方法-"躺平"
    * 方案二:不再抽象,实现继承自父类中的所有未实现的抽象方法-"父债子偿"*/
    class Banana extends Fruit{
        @Override
        public void grow() {
            System.out.println("一串香蕉老沉了~");
        }
        @Override
        public void clean2() {
            System.out.println("香蕉不用洗,香蕉喜欢被扒皮");
        }
    }
    

    拓展

    总结:abstract注意事项

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

    1. private:被私有化后,子类无法重写,与abstract相违背。
    2. static:静态优先于对象存在,存在加载顺序问题。
    3. final:被final修饰后,无法重写,与abstract相违背。
  • 相关阅读:
    Network Embedding 论文小览
    DLRS(深度学习应用于推荐系统论文汇总--2017年8月整理)
    深度语义匹配模型-DSSM 及其变种
    python 按值排序
    python 日期排序
    推荐领域数据集
    EPS 转 pdf 在线
    梯度下降法的三种形式BGD、SGD以及MBGD
    Daily paper -Science 2006: Experimental Study of Inequality and Unpredictability in an Artificial Cultural Market (探究群体行为对商品销量的影响)
    2017年Nature文章“Millions of online book co-purchases reveal partisan differences in the consumption of science”阅读笔记
  • 原文地址:https://www.cnblogs.com/elliottmoo/p/15682016.html
Copyright © 2011-2022 走看看