436-449练习/异常(未完)

一、练习

package com.alice.innerclass_.innerclass03;

/**
 * @author alice_huijing
 * @version 1.0
 */

/**
 * 第一题:
 *  以下代码的执行结果
 */
public class Homework01 {
//    public static void main(String[] args) {
//        Car c = new Car(); // 创建一个实例化对象,初始化静态,普通,最后构造器,price = 9, color = red,无参构造方法
//        Car c1 = new Car(100);  // 创建一个实例化对象,静态信息只加载一次,因为类已经加载过了,执行有参构造price=100,color=red
//        System.out.println(c); //9.0 red
//        System.out.println(c1);//100.0	red
//    }
}

class Car {
    double price = 10;  // 类型为double,结果保留小数
    static String color = "white"; // 静态属性,只加载一次,实例化对象共享属性
    public String toString() {  // 打印对象引用返回这个
        return price + "\t" + color;
    }
    public Car() {
        this.price = 9;
        this.color ="red";
    }
    public Car(double price) {
        this.price = price;
    }
}

/**
 * 第二题:
 *  1.在Frock类中声明私有的静态属性currentNum,为int类型,初始值为100000,作为衣服出厂的序列号起始值。
 *  2.声明公有的静态方法getNextNum,作为生成上衣唯一序列号的方法。每次调用,将currentNum增加100,并且作为返回值。
 *  3、在TestFrock类的main方法中,分别两次调用getNextNum方法,获取序列号并打印输出。
 *  4,在Frock类中声明serialNumber(序列号)属性,并提供对象的get方法;
 *  5,在Frock类的构造器中,通过调用getNextNum方法为Frock对象获取唯一的序列号,赋给serialNumber属性
 *  6、在TestFrock类的main方法中,分别创建三个Frock对象,并打印三个对象的序列号,验证是否为按100递增。
 */
class Frock {
    private static int currentNum = 100000;
    private int serialNumber;
    public Frock() {
        serialNumber = getNextNum();
    }
    public static int getNextNum() {
        currentNum += 100;
        return currentNum;
    }

    public int getSerialNumber() {
        return serialNumber;
    }
}
class TestFrock {
    public static void main(String[] args) {
        System.out.println(Frock.getNextNum());
        System.out.println(Frock.getNextNum());
        Frock frock = new Frock();
        Frock frock1 = new Frock();
        Frock frock2 = new Frock();
        System.out.println(frock.getSerialNumber());
        System.out.println(frock1.getSerialNumber());
        System.out.println(frock2.getSerialNumber());
    }
}
// 2
package com.alice.innerclass_.innerclass03;

/**
 * @author alice_huijing
 * @version 1.0
 */

/**
 * 第三题:
 * 按要求实现下列问题
 * 1、动物类Animal包含了抽象方法shout();
 * 2、Cat类继承了Animal,并且实现了方法shout,打印“猫会喵喵叫”
 * 3、Dog类继承了Animal,并且实现了方法shout,打印“狗会汪汪叫”
 * 4、在测试类中实例化对象Animal cat = new Cat(),并调用cat的shout方法
 * 5、在测试类中实例化对象Animal dog = new Dog(),并调用dog的shout方法
 */
public class Homework02 {
//    public static void main(String[] args) {
//        Animal cat = new Cat();  // 上转型 编译类型是Animal,可以点出的方法有shout
//        Animal dog = new Dog();  // 上转型 编译类型是Animal,可以点出的方法有shout
//        // 由于动态绑定机制的存在,并且这些类中重写了父类Animal中的shout方法,所以产生了多态
//        cat.shout(); // 猫会喵喵叫
//        dog.shout(); // 狗会汪汪叫
//    }
}

abstract class Animal {  // 有抽象方法之后,这个类必须是抽象类
    abstract void shout();
}

class Cat extends Animal {  // 继承了抽象类就需要实现抽象类中所有的抽象方法
    @Override
    void shout() {
        System.out.println("猫会喵喵叫");
    }
}

class Dog extends Animal {
    @Override
    void shout() {
        System.out.println("狗会汪汪叫");
    }
}

/**
 * 第四题
 * 1、计算器接口具有work方法,功能是运算,有一个手机类Cellphone,定义方法testWork测试计算功能
 * 调用计算接口的work方法,
 * 2、要求调用CallPhone对象的testWork方法,使用上匿名内部类
 */
interface Calculator {
    double work(double... nums);
}

class Cellphone {
    public Calculator testWork() {
        return new Calculator() {
            // 匿名内部类在方法中,当前运行类型是Calculator,但是运行类型是Cellphone$1
            // 所以这里能够点出work,但是运行的是匿名内部类的重写的work,new Calculator就相当于是实现的什么接口
            // 返回的是编译类型,但是一旦调用运行则是运行类型
            @Override
            public double work(double... nums) {
                System.out.println(getClass());  // Cellphone$1
                double sum = 0;
                for (int i = 0; i < nums.length; i++) {
                    sum += nums[i];
                }
                return sum;
            }
        };
    }

    public void testWorkA(Calculator calculator, double... nums) {
        double res = calculator.work(nums);  // 当前编译类型能够点出work,但是执行的时候还是使用匿名内部类重写的方法
        System.out.println("老韩的方式的结果 = " + res);
    }
}

class CellphoneX implements Calculator {  // 类实现一个接口,就要重写这个接口中的所有方法
    @Override
    public double work(double... nums) {
        System.out.println(getClass());  // CellphoneX
        double sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
        }
        return sum;
    }
}

class Test01 {
    public static void main(String[] args) {
        double sum = new CellphoneX().work(20, 100.45, 88, 99.9, 3.14);
        System.out.println("使用传统的方式:" + sum);
        double sum1 = new Cellphone().testWork().work(20, 100.45, 88, 99.9, 3.14);  // 编译类型点出work,一旦运行
        // 执行Cellphone$1重写的方法
        System.out.println("使用匿名内部类的方式:" + sum1);
        new Cellphone().testWorkA(new Calculator() {  // 直接通过传入匿名内部类的方式
            @Override
            public double work(double... nums) {
                System.out.println(getClass());  // Test01$1
                double sum = 0;
                for (int i = 0; i < nums.length; i++) {
                    sum += nums[i];
                }
                return sum;
            }
        }, 20, 100.45, 88, 99.9, 3.14);  // 这种方式更加灵活,可以调整计算的方式
    }
}
// 3
package com.alice.innerclass_.innerclass03;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Homework03 {
    public static void main(String[] args) {
        A a = new A();  // 创建A实例化对象调用bb,编译类型为A所以可以点出bb,运行类型为A,所以调用的是AA的bb方法
        a.bb();
        System.out.println("A  " + a);
    }
}

/*
    内部类:
    1、编写一个类A,在类定义局部内部类B,在B中有一个私有常量name,有一个方法show()打印常量name,进行测试
    2、进阶:A中也定义一个私有的变量name,在show方法中打印测试
 */
class A {
    private String name = "bob";
    public void bb() {
        class B {  // 这个类在方法体中,使用class修饰,这个类是局部内部类,还可以定义在普通代码块中
            public B(String name) {  // 常量不能通过set方法进行修改,这里使用构造器进行添加
                this.NAME = name;
            }

            private final String NAME;  // 常量需要final关键字修饰,按照规范常量名大写

            public void show() {
                System.out.println("show() 方法打印局部内部类常量name = " + this.NAME);
                System.out.println("show() 方法中打印外部类的变量name = " + A.this.name);
                // 如果局部内部类和外部类重名可以使用外部类的类名.this.这个成员
                // 这里的this指的是b,然后A.this指的是a
                System.out.println(this);
                System.out.println("A  " + A.this);
            }
        }
        B b = new B("alice");  // 局部内部类在外部其他类中无法创建,所以需要在这个方法中创建,将这个返回出去也可以在外部其他调用
        b.show();
    }
}
// 4
package com.alice.innerclass_.innerclass03;

import com.alice.houserent.domain.House;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Homework04 {
    public static void main(String[] args) {
    /*
        5、实例化Person对象“唐僧”,要求一般情况下使用Horse作为交通工具,遇到大河的时候使用
            Boat作为交通工具。
    */
//        Person person = new Person("唐僧", Factory.getHorse());
//        person.getVehicles().work();
//        System.out.println("遇到大河了,需要使用船作为交通工具。");
//        person.setVehicles(Factory.getBoat());
//        person.getVehicles().work();
        Person tang = new Person("唐僧", new Horse());
        tang.common();
        tang.passRiver();
        tang.common();
        tang.passRiver();
        tang.passRiver();
        tang.passRiver();
        tang.passRiver();
        tang.passFireHill();
        /*
            Person person = new Person("唐僧", Factory.getHorse());
            person.getVehicles().work();
            System.out.println("遇到大河了,需要使用船作为交通工具。");
            person.setVehicles(Factory.getBoat());
            person.getVehicles().work();

            这个地方老韩将
            要求一般情况下使用Horse作为交通工具,遇到大河的时候使用Boat作为交通工具
            这里封装成方法来进行使用,这里体现了一个封装的思想。这里我没有封装。
         */

    }
}

/*
    1、有一个交通工具接口类Vehicles,有work接口
    2、有Horse类和Boat类分别实现Vehicles
    3、创建交通工具工厂类,有两个方法分别获取交通工具Horse和Boat
    4、有Person类,有name和Vehicles属性,在构造器中为两个属性赋值
    5、实例化Person对象“唐僧”,要求一般情况下使用Horse作为交通工具,遇到大河的时候使用
        Boat作为交通工具。
 */
interface Vehicles { // Vehicles是交通工具的意思
    void work();  // 要求实现接口类的类是实现这个方法
}

class Horse implements Vehicles {  // 马这个交通工具

    @Override
    public void work() {
        System.out.println("白龙马蹄朝西,后面跟着唐僧的三徒弟。");
    }
}

class Boat implements Vehicles {  // 船这个交通工具

    @Override
    public void work() {
        System.out.println("让我们荡起双桨,小船儿推开波浪。。");
    }
}

//class Factory {
//    public Horse getHorse() {
//        return new Horse();
//    }
//
//    public Boat getBoat() {
//        return new Boat();
//    }
//}  , 因为这是一个工厂类,相当于是一个工具类,我们一般不会创建这个工具类,这里应该写成一个静态的方法。
// 老韩提醒1.
class Factory {
    // 为了保持一匹马
    private static Horse horse = new Horse();  // 饿汉式
    public static Horse getHorse() {  // 这里还需要注意一点,这里我也没有考虑,这里不能直接返回一匹新的马,需要一直是白龙马
//        return new Horse();
        return horse;
    }

    public static Boat getBoat() {
        return new Boat();
    }

    public static Plane getPlane() {
        return new Plane();
    }
}

class Person {
    private String name;
    private Vehicles vehicles;

    // 在创建人对象的时候,先分配一个交通工具
    // 如何不浪费,在创建对象的时候,传入的交通工具对象
    // 在我们取马或者是船的时候去判断一下是否已经有了这个工具
    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }

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

    public void setVehicles(Vehicles vehicles) {
        this.vehicles = vehicles;
    }

    public String getName() {
        return name;
    }

    public Vehicles getVehicles() {
        return vehicles;
    }

    public void passRiver() {
//        Boat boat = Factory.getBoat();
//        boat.work();
        if(!(vehicles instanceof Boat)) {  // 是空或者是马
            // 但是如果都是(vehicles == null)判断为空,如果交通工具是马也是不空的,如果交通工具是船也是不空的,这样就都是马了。
            // 所以需要使用instanceof
            vehicles = Factory.getBoat();
        }
        vehicles.work();
    }

    public void common() {
//        Horse horse = Factory.getHorse();
//        horse.work();
        if(!(vehicles instanceof House)) {  // 是空或者是船
            vehicles = Factory.getHorse();
        }
        vehicles.work();
    }

    public void passFireHill() {
        if(!(vehicles instanceof Plane)) {  // 是空或者是船
            vehicles = Factory.getPlane();
        }
        vehicles.work();
    }
}

// 思考:最后再增加一个情况,如果唐僧过火焰山,需要使用飞机,这里就体现程序的扩展性了,基于前面的结构我们非常好扩展。
// 这里可以直接增加一个飞机类
// 在工厂再返回一个飞机
// 在人中再增加一个过火焰山的情况
class Plane implements Vehicles {
    @Override
    public void work() {
        System.out.println("过火焰山,使用飞机。。。");
    }
}
//5
package com.alice.innerclass_.innerclass03;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Homework05 {
    public static void main(String[] args) {
        new Car01(39.9);
        new Car01(-2);
        Car01 c = new Car01(42);
        c.getAir().flow();
    }
}

/*
    第七题:
        内部类练习
        有一个Car类,有属性temperature温度,车内有Air空调类,有吹风的功能flow,
        Air会监视车内的温度,如果温度超过40度则吹冷风,如果温度低于0度则吹暖气,如果在这之间
        则关闭空调。实例化具有不同温度的Car对象,调用空调的flow方法,测试空调吹的风是否正确。
 */
class Car01 {
    private double temperature;

    public Car01(double temperature) {
        this.temperature = temperature;
        new Air().flow();
    }

    class Air {
        void flow() {
            if (Car01.this.temperature > 40) {
                System.out.println("正在吹冷风。。。");
            } else if (Car01.this.temperature < 0) {
                System.out.println("正在吹暖风。。。");
            } else {
                System.out.println("空调关闭中。。。");
            }
        }
    }

    // 老韩通过返回Air对象的方式
    public Air getAir() {
        return new Air();
    }
}
// 6
package com.alice.innerclass_.innerclass03;

import java.util.Arrays;

/**
 * @author alice_huijing
 * @version 1.0
 */

/*
    第八题
        枚举类
        1、创建一个Color枚举类
        2、有RED,BLUE,BLACK,YELLOW,GREEN这五个枚举值
        3、Color有三个属性redValue,greenValue,blueValue,
        RED(红): (255, 0, 0)

        BLUE(蓝): (0, 0, 255)

        BLACK(黑): (0, 0, 0)

        YELLOW(黄): (255, 255, 0)(红+绿混合)

        GREEN(绿): (0, 255, 0)
        4、创建构造方法,参数包括这三个属性
        5、每个枚举值都需要给这三个属性赋值
        6、定义接口,里面有方法show,要求Color实现该接口
        7、show方法中显示三属性的值
        8、将枚举对象在switch语句中匹配使用
 */
public class Homework06 {
    public static void main(String[] args) {
        Color[] values = Color.values();
        System.out.println("颜色数组->" + Arrays.toString(values));
        for (Color value: values) {
            value.useInSwitch();
        }

    }
}

interface ColorInterface {
    void show();
}

enum Color implements ColorInterface {
    RED(255, 0, 0), BLUE(0, 0, 255),
    BLACK(0, 0, 0), YELLOW(255, 255, 0),
    GREEN(0, 255, 0);
    private int redValue;
    private int greenValue;
    private int blueValue;

    Color(int redValue, int greenValue, int blueValue) {
        this.redValue = redValue;
        this.greenValue = greenValue;
        this.blueValue = blueValue;
    }

    @Override
    public void show() {
        System.out.println("(" + redValue + ',' + greenValue + ',' + blueValue + ")");
    }

    public void useInSwitch() {
        switch (this.toString()) {
            // 这里我是按照字符串来判断的,其实还可以支持枚举类型,这里我忘记了。,也就是this,然后判断不用加双引号
            case "RED":
                System.out.println("红色的RGB是:");
                show();
                break;
            case "BLUE":
                System.out.println("蓝色的RGB是:");
                show();
                break;
            case "BLACK":
                System.out.println("黑色的RGB是:");
                show();
                break;
            case "YELLOW":
                System.out.println("黄色的RGB是:");
                show();
                break;
            case "GREEN":
                System.out.println("绿色的RGB是:");
                show();
                break;
        }
    }
}

二、异常(未完)

// 01
package com.alice.innerclass_.innerclass03.Exception_;

/**
 * @author alice_huijing
 * @version 1.0
 */

/*
    异常对应的英文单词是Exception
    这个章节主要讲解的内容:
    1、异常的概念
    2、异常的体系图,重要
    3、常见的异常
    4、异常处理概念
    5、异常处理分类
    6、自定义异常
    7、throw和throws的对比
    首先还是通过一段代码引出异常和异常处理机制

 */
public class Exception01 {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 0;
        // 如果程序员觉得一段代码可能出现异常,或者说问题,可以使用try catch异常处理机制来解决,从而保证程序的
        // 健壮性和容错性。
        // 为了快捷的使用这个语法,我们只需要将可能出现异常的语句块使用光标选中
        // 然后Ctrl + Alt + t然后选择try catch即可
        try {
            int res = num1 / num2;  // 可以看到这里的语法并没有什么错误,但是当我们运行的时候就会抛出异常,这里除以0
        } catch (Exception e) {
            // 如果进行异常处理,那么即使出现了异常,程序也可以继续执行。
            // e.printStackTrace();  // 这里程序的异常还是抛出了,但是并没有什么影响,程序还是继续执行,因为这里是直接抛出,所以是红色
            // 也可以打印
            System.out.println(e.getMessage());  // 将你异常的原因输出
        }
        // 抛出异常之后程序终止,后面的程序不会再被运行ArithmeticException
        // Exception in thread "main" java.lang.ArithmeticException: / by zero
        // 这样并不好,因为软件如果出现这样的问题,直接不能执行,这样的软件健壮性就太差了,一点点错误导致整个软件崩溃
        // 一个软件不可避免的会出现异常,但是这样不好,我们只需要保证没有语法错误,异常不能忍受。
        // 所以Java提供了一个异常处理机制来解决这个问题。因为这个问题不是什么致命的问题。

        System.out.println("程序继续运行。。。");
    }
}
// 02
package com.alice.innerclass_.innerclass03.Exception_;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Exception02 {
}

/*
    接下来对异常进行一个介绍
    基本概念:
        Java语言中,将程序执行中发生的不正常情况称为“异常”,开发过程当中语法错误和逻辑错误不是异常(这点需要强调)
    执行过程中所发生的异常可以分成两类:
        1Error错误,Java虚拟机无法解决的严重问题。如JVM系统内部错误,资源耗尽等严重的情况。
        比如StackOverflowError栈溢出和OOM out of memory,Error是严重错误,程序会崩溃

        2Exception:其他因为编程错误或者偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如
        空指针访问,试图读取不存在的文件,网络连接中断等等,Exception分成两大类,运行时异常和编译时异常。

        运行时异常和编译时异常发生的时间不一样
        运行时异常是在程序运行时,发生的异常
        编译时异常是在编程时,编译器检查出的异常。

        前面的除零就是一个运行时异常。
 */
// 03
package com.alice.innerclass_.innerclass03.Exception_;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Exception03 {
    public static void main(String[] args) {
//        Throwable
    }
}

/*
    异常体系图,异常体系图是一个重点,这里直接画图
    在main中输入Throwable,然后我们进入到这个类中
    右键Diagrams然后show Diagram...可以看到IDEA帮我们生成的图
    这里的Throwable就相当于是所有异常类的根类
    接下来点击这个根类,然后右键Show Implementations可以查看到实现类
    下面所有实现类或者说是接口有哪些,接下来会弹出一个弹窗我们输入Error
    可以将该类添加到当前这幅图当中
    这个Error是这里异常根类的一个子类,就是刚刚将的异常可以分成两大类的
    第一个Error
    在Error下面还有StackOverflowError栈溢出
    还有内存溢出OutOfMemoryError

    除了Error之外还有一个子类是Exception
    在Exception下面还有一个RuntimeException
    而在RuntimeException有几个常见的异常
    比如空指针异常
    NullPointerException
    比如算术异常
    ArithmeticException,就是刚才除零的
    比如数组索引越界的异常
    ArrayIndexOutOfBoundsException
    还有类型转换异常
    ClassCastException
    还有数字格式异常
    NumberFormatException
    这些都是运行时异常

    还有一组是编译时异常
    也是属于Exception
    FilNotFoundException
    以上都是最常见的

    最后我们再将Throwable的父类打印出来,可以点击它然后右键show Parents
    虚线表示实现了这个接口I
    Error是一个致命错误,无法通过异常捕获,程序直接会死
    而异常这块除了编译异常还有运行异常

    小结:
        1、异常分成两大类,运行时异常和编译时异常。
        2、运行时异常,编译器不要求强制处理的异常。一般是指编程的时候的逻辑错误,是程序员应该避免的异常,
        比如前面编译器不会知道这里是除的是零,因为当前语法正确。
        java.lang.RuntimeException类以及它的子类都是运行时异常。
        3、对于运行时异常,可以不作处理,因为这类异常很普遍,因为这类异常比较普遍,如果全部处理可能会对程序的可读性
        和运行效率产生影响。
        4、编译时异常,是编译器要求必须处置的异常。
 */
// 04
package com.alice.innerclass_.innerclass03.Exception_;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Exception04 {
    public static void main(String[] args) {
        // 1、NullPointerException空指针异常
        String name = "alice";
        System.out.println(name.length());  // 现在name是不为空的,正常统计个数5
        String nameNull = null;  // 当为空的时候就是null.length()这里会抛出异常
//        System.out.println(nameNull.length());  // Exception in thread "main" java.lang.NullPointerException
        // 2、ArithmeticException是数学运算异常,这个之前除以零的时候见到过了。
        // 3、ArrayIndexOutOfBoundsException数组下标越界异常
        int[] arr = {1, 2, 4};
//        for (int i = 0; i <= arr.length; i++) {  // 这里会抛出数组下标越界异常,因为arr[3]这里刚好超过了能够访问的max索引arr[2]
//            System.out.println(arr[i]);  // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
//        }
        // 4、ClassCastException类型转换异常
        A b = new B();  // 编译类型是A,运行类型是B,B继承了A,这是一个向上转型,指向的是B,是A的b指向了B
        B b2 = (B)b;  // 编译类型为A想要转换成B,这是一个向下转型,因为原本指向的是B所以可以转换
//        C c2 = (C)b;  // 因为b现在编译类型和运行类型都是B,B和C没有什么继承关系B不继承C,C不继承B,并且b现在指向的是B不是C,所以不能转
        // Exception in thread "main" java.lang.ClassCastException
//        5、NumberFormatException数字格式不正确异常[]
        String str = "123";
        int num = Integer.parseInt(str);  // 将一个整数字符串转换为一个整型int可以
        String str1 = "hello";
        int num1 = Integer.parseInt(str1);  // 这个字符串是一个英文字符串
        // Exception in thread "main" java.lang.NumberFormatException
    }
}
class A {}
class B extends A{}
class C extends A{}
/*
    常见的运行时异常
    常见的运行时异常包括:
        1、NullPointerException空指针异常
            当应用程序试图在需要对象的地方使用null时,抛出该异常
        2、ArithmeticException数学运算异常
            当出现异常的运算条件时,抛出此异常,比如除以零会抛出此类的一个实例。
        3、ArrayIndexOutOfBoundsException数组下标越界异常
            使用非法的索引方法数组时抛出的异常。如果索引为负或者大于等于数组大小,则该索引为非法索引
        4、ClassCastException类型转换异常
            当试图将对象强转为不是实例的子类的时候,抛出该异常,
        5、NumberFormatException数字格式不正确异常[]
            NumberFormatException数字格式不正常异常
            当应用程序试图将字符串转换成一种数值类型,但是该字符串不能转换为适当格式的时候会抛出该异常。
            使用异常我们可以确保输入是满足条件的数字。
 */
// 05
package com.alice.innerclass_.innerclass03.Exception_;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Exception05 {
    public static void main(String[] args) {
//        // 第一题
//        String friends[]={"tom","jack","milan"};
//        for(int i = 0; i < 4; i++) {  // 这里多了一个3,会出现数组下标越界的异常
//            System.out.println(friends[i]);
//        }
//        // 第二题
//        Cat c = new Cat();
//        cat = null;
//        System.out.println(cat.name);  // null.name空指针异常
//        // 第三题
//        public class AAA {
//            int x;
//            public static void main(String[] args) {
//                int y;
//                AAA a = new AAA();
//                y = 3/a.x;  // 类成员被默认初始化为0,所以这里产生一个除零的异常-数学运算异常
//                System.out.println("program ends ok!");
//            }
//        }
//        // 第四题
//        class Person {
//            public static void main(String[] args) {
//                Object obj = new Date();  // 一个上转型,当前编译类型为Object,当前运行类型为Date,指向Date
//                Person person;
//                person = (Person)obj;  // 这里应该转成Date可以,而Person和Date之间没有任何的关系。转不了
//                System.out.println(person);  // ClassCastException类型转换异常
//            }
//        }
    }
}
/*
    编译异常
    介绍:
        编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。
    常见的编译异常
        编译异常一般发生在网络,数据库和文件的时候
        SQLException 操作数据库的时候,查询表可能会发生异常
        IOException  操作文件的时候,发生的异常
        FileNotFoundException 当操作一个不存在的文件的时候发生的异常
        ClassNotFoundException 加载类,而该类不存在的时候发生异常
        EOFException 操作文件,到文件结尾,发生异常
        IllegalArgumentException 参数异常
 */

/*
    关于异常的课堂练习
    看看下面代码是否正确,为什么。
 */
// 06
package com.alice.innerclass_.innerclass03.Exception_;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Exception06 {
    public static void main(String[] args) {
        // 第一个小细节。
        // 注意使用快捷键来快速生成异常处理代码
        // Ctrl + Alt + t
//        try {  // 比如这段代码可能会出现异常,先选中这段代码,然后快捷键选择try catch
//            String str = "hello";
//            int a = Integer.parseInt(str);
//            System.out.println("数字:" + a); // 前面出现了异常直接跳到catch中执行,这行代码不会被执行。
//        } catch (NumberFormatException e) {
//            System.out.println("异常信息为:" + e.getMessage());
//        }
//        System.out.println("后面的代码正常执行。");
        // 第二个小细节
//        try {  // 比如这段代码可能会出现异常,先选中这段代码,然后快捷键选择try catch
//            String str = "123";
//            int a = Integer.parseInt(str);
//            System.out.println("数字:" + a);  // 这里可以正常通过转换
//        } catch (NumberFormatException e) {  // catch中的代码不会被执行,因为没有异常,也就不会捕获到异常
//            System.out.println("异常信息为:" + e.getMessage());
//        }
//        System.out.println("后面的代码正常执行。");
        // 第三个小细节
        try {
            String str = "123";
            int a = Integer.parseInt(str);
            System.out.println("数字:" + a);
        } catch (NumberFormatException e) {
            System.out.println("异常信息为:" + e.getMessage());
        } finally {  // 管你有没有异常都会执行。
            System.out.println("finally代码被执行。。。");
        }
        System.out.println("后面的代码正常执行。");
        // tip:IDEA的终端右上角的小齿轮的View Mode的Float可以将终端浮动哦,相当于我们执行的时候会有终端弹出。
//        // 第四个小细节,Exception作为这些异常的父类可以都捕获,但是只能捕获先发生的。
//        try {
//            Person person = new Person();
//            person = null;  // 出现一个异常直接抛出,后面的直接不执行。
//            System.out.println(person.getName());  // 空指针异常
//            int n1 = 10;
//            int n2 = 0;
//            int res = n1 / n2; // 算数运算异常
//        } catch (Exception e) {
//            System.out.println(e.getMessage());  // 因为这两种异常都是Exception的子类,所以都能够捕获到
//        } finally {
//            System.out.println("不管是否异常都会执行。");
//        }
        // 第五个小细节,可以写多个catch就可以捕获各种指定的异常,要求子类异常写道前面,父类异常写道后面
        // 因为如果父类写在前面就没有意义了,后面的异常永远不会被执行
//        try {
//            Person person = new Person();
//            person = null;  // 出现一个异常直接抛出,后面的直接不执行。
//            System.out.println(person.getName());  // 空指针异常
//            int n1 = 10;
//            int n2 = 0;
//            int res = n1 / n2; // 算数运算异常
//        } catch (NullPointerException e) {  // 单独捕获空指针异常
//            System.out.println("空指针异常=" + e.getMessage());
//        } catch (ArithmeticException e) {
//            System.out.println("算数异常=" + e.getMessage());
//        } catch (Exception e) {
//            System.out.println(e.getMessage());
//        } finally {
//            System.out.println("不管是否异常都会执行。");
//        }
        try {
            int n1 = 10;
            int n2 = 0;
            System.out.println(n1 / n2);
        } finally {
            System.out.println("执行了finally...");
        }
        System.out.println("程序继续执行...");  // 因为不会捕获异常,所以直接崩了,这句代码不会执行到。程序退出。
    }
}

/*
    异常处理的两种方式
    异常处理
    基本介绍:
        异常处理就是当异常发生的时候,对异常处理的方式
    异常处理的方式:
        1、try-catch-finally方式
            程序员在代码中捕获发生的异常,自行进行处理
        2、throws
            将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理人就是JVM

    细节:
        1、如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块。
        2、如果异常没有发生,则顺序执行try的代码块,不会进入到catch。
        3、如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等,则使用下面的finally这个)
        4、可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后面,子类异常在前面,
        比如Exception在后面,NullPointerException在前面,如果发生异常,只会匹配一个catch。
        5、第五点可以只使用try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。
        应用场景是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
        本质是没有捕获异常,程序结束。
 */

三、附图

image

posted @ 2025-05-16 23:17  请叫我虾  阅读(21)  评论(0)    收藏  举报