JavaStudy2(枚举类+oop高级部分练习+异常)—B站hsp

本文介绍了Java中枚举类的使用,包括自定义枚举类和使用enum关键字,以及面向对象高级实践,涉及异常捕获和处理的最佳实践。通过实例演示了如何创建固定值的季节对象、注解的运用和异常的throw与throws区别。
摘要由CSDN通过智能技术生成

JavaStudy2(枚举类+oop高级部分练习+异常)—B站韩顺平

1.枚举类

1.1枚举类入门

要求创建季节(Season) 对象,请设计并完成。Enumeration01.java

class Season{//类

private String name;

private String desc;//描述

//构造器

//getXX

//setXX

}

代码:

public class Enumeration01 {
    public static void main(String[] args) {
        Season spring = new Season("春天","温暖");
        Season winter = new Season("冬天","温暖");
        Season summer = new Season("夏天","温暖");
        Season autumn = new Season("秋天","温暖");
        //因为对于季节而已,他的对象(具体值),是固定的四个,不会有更多
        //安老师的这个设计类的思路,不能体现季节是固定的四个对象
        // 因此,这样的设计不好===> 枚举类[枚: 一个一个 举: 例举 , 即把具体的对象一个一个例举出来的类
        // 就称为枚举类]
    }
}
class Season{
    private String name;//季节名
    private String desc;//描述

    public Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

1.2分析问题

1.2.1创建Season对象有以下特点
  1. 季节的值是有限的几个值(spring, summer, autumn, winter)
  2. 只读,不需要修改。
1.2.2解决方案-枚举
  1. 枚举对应英文(enumeration, 简写 enum)

  2. 枚举是一组常量的集合。

  3. 可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。

1.2.3枚举的二种实现方式
1.自定义类实现枚举
1.1自定义类实现枚举-应用案例
  1. 不需要提供setXxx方法,因为枚举对象值通常为只读
  2. 对枚举对象?属性使用fianl+static共同修饰,实现底层优化
  3. 枚举类对象名通常使用全部大写,常量命名规范
  4. 枚举对象根据需要,也可以有多个属性
1.2代码演示:
public class Enumeration02 {
    public static void main(String[] args) {

    }
}
//演示自定义枚举类
class Season1{
    private String name;//季节名
    private String desc;//描述
    //定义了四个对象
    public static Season1 SPRING = new Season1("春天","温暖");
    public static Season1 WINTER = new Season1("冬天","温暖");
    public static Season1 SUMMER = new Season1("夏天","温暖");
    public static Season1 AUTUMN = new Season1("秋天","温暖");
    //1.将构造器私有化,目的防止直接new
    //2.去掉setxxx方法,防止属性被更改
    //3.在Season内部 ,直接创建固定的对象
    //4.优化,可以加入 final 修饰符
    private Season1(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
1.3小结:进行自定义类实现枚举,有如下特点:
  1. 构造器私有化
  2. 本类内部创建一组对象【四个,春夏秋冬】
  3. 对外暴露对象(通过为对象添加public final static 修饰符)
  4. 可以提供get方法,但是不要提供set
2.使用 enum 关键字实现枚举
2.1enum 关键字实现枚举-快速入门
//如果使用了 enum 来实现枚举类
//1. 使用关键字 enum 替代 class
//2.将public static Season3 SPRING = new Season3("春天","温暖"); 直接替换为
//  SPRING("春天","温暖"); 解读 常量名(实参列表)
//3.如果有多个常量(对象),使用","逗号隔开即可
//4.如果使用enum 来实现枚举类,要求将定义的常量对象,写在枚举类内最前面

代码演示:

public class Enumeration03 {
    public static void main(String[] args) {
        System.out.println(Season3.SPRING);
        System.out.println(Season3.SUMMER);
    }
}

//演示使用enum 关键字来实现枚举类
enum Season3{ //类

//    //定义了四个对象
//    public static Season3 SPRING = new Season3("春天","温暖");
//    public static Season3 WINTER = new Season3("冬天","温暖");
//    public static Season3 SUMMER = new Season3("夏天","温暖");
//    public static Season3 AUTUMN = new Season3("秋天","温暖");
    //如果使用了 enum 来实现枚举类
    //1. 使用关键字 enum 替代 class
    //2.将public static Season3 SPRING = new Season3("春天","温暖"); 直接替换为
    //  SPRING("春天","温暖"); 解读 常量名(实参列表)
    //3.如果有多个常量(对象),使用","逗号隔开即可
    //4.如果使用enum 来实现枚举类,要求将定义的常量对象,写在枚举类内最前面
    SPRING("春天","温暖"),WINTER("冬天","温暖"),SUMMER("冬天","温暖"),AUTUMN("秋天","温暖");
    private String name;//季节名
    private String desc;//描述

    private Season3(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Season3{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}
2.2enum 关键字实现枚举注意事项
  1. 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类[如何证明],老师使用 javap 工 具来演示

  2. 传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”), 这里必 须知道,它调用的是哪个构造器.

  3. 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略

在这里插入图片描述

  1. 当有多个枚举对象时,使用,间隔,最后有一个分号结尾

  2. 枚举对象必须放在枚举类的行首

2.3enum 关键字实现枚举-课堂练习

在这里插入图片描述

  1. 下列输出是什么
public class EnumExercise01 {
    public static void main(String[] args) {
        Gender boy = Gender.BOY; //ok
        Gender boy2 = Gender.BOY; //ok
        System.out.println(boy);//输出BOY //本质就是调用Gender的父类Enum的toSring方法
        System.out.println(boy == boy2);//true
    }
}
enum Gender{
    BOY,GIRL;
}
2.4enum 常用方法说明

enum 常用方法应用实例

  1. toString():返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息

  2. name():返回当前对象名(常量名),子类中不能重写

  3. ordinal():返回会当前对象的位置号,默认从0开始

  4. values:返回当前枚举类中所有的常量
    在这里插入图片描述

  5. valuesOf():将字符串转换成枚举对象,要求字符串必须为已有常量名,否则报异常!

  6. compareTo():比较两个枚举常量,比较的就是编号!

public class EnumMethod {
    public static void main(String[] args) {
        //使用Season4枚举类,来演示各种方法
        Season4 spring = Season4.SPRING;
        //输出枚举对象的名字
        System.out.println(spring.name());//SPRING
        //ordinal()输出的是该枚举对象的次序/编号,从0开始编号
        //  SPRING 枚举对象是第一个,因此输出 0
        System.out.println(spring.ordinal());//0
        //从反编译可以看到 values 方法,返回 Season4[]
        //含有定义的所有枚举类对象
        Season4[] values = Season4.values();
        System.out.println("====遍历取出枚举对象(增强for)====");
        for (Season4 season4 : values) {//增强for循环
            System.out.println(season4);
        }
        //valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常
        //执行流程
        //1.根据你输入的"AUTUMN"到Season2的枚举对象去查找
        //2.如果找到了,就返回,如果没有找到,就报错
        Season4 spring1 = Season4.valueOf("SPRING");
        System.out.println("autumn1 = " + spring1);
        System.out.println(spring1 == spring);
        //compareTo:比较两个枚举常量,比较的就是编号
        //1.就是把Season4.SPRING 枚举对象的编号 和 Season4.AUTUMN枚举对象的编号作比较
        /*
          public final int compareTo(E o) {

            return self.ordinal - other.ordinal;本身对象和其他对象编号相减
    }
               Season4.SPRING 的编号[0] - Season4.AUTUMN 的编号[3]
         */
        System.out.println(Season4.SPRING.compareTo(Season4.AUTUMN));//-3
    }
}

enum Season4{ //类
    SPRING("春天","温暖"),WINTER("冬天","温暖"),SUMMER("冬天","温暖"),
    AUTUMN("秋天","温暖");
    private String name;//季节名
    private String desc;//描述

    Season4() {//无参构造
    }

    private Season4(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Season3{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }

enum 细节

  1. 使用enum关键字后,就不能在继承其他类了,因为enum会隐式继承Enum,而Java是单继承机制
  2. enum实现的枚举类,任然是一个类,所以还是可以实现接口的。

代码演示:

public class EnumDetail {
    public static void main(String[] args) {
        Music.CLASSICMUSIC.playing();//播放音乐
    }
}
//1. 使用enum关键字后,就不能在继承其他类了,因为enum会隐式继承Enum,而Java是单继承机制
//2. enum实现的枚举类,任然是一个类,所以还是可以实现接口的。
interface IPlaying{
    public void playing();
}
enum Music implements IPlaying{
    CLASSICMUSIC;

    @Override
    public void playing() {
        System.out.println("播放音乐");
    }
}

2.注解

2.1注解的理解

  1. 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。

  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。

  3. 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等

2.2基本的注解Annotation介绍

​ 使用Annotation是要在其前面加@符号,并把该Annotation当成一个修饰符使用。用于修饰它支持的程序元素。

  1. @Override:限定的某个方法,是重写父类的方法,该注解只能用于方法
  2. @Deprecated:用于表示某个程序元素(类,方法等)已过时
  3. @SuppressWarnings:抑制编译器警告

2.3基本的 Annotation 应用案例

  1. @Override 注解的案例

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码演示:

public class Override_ {
    public static void main(String[] args) {

    }
}class Father{//父类
    public void fly(){
        System.out.println("Father fly...");
    }
    public void say(){

    }
}
    class Son extends Father {//子类
    //解读
        // 1. @Override 注解放在 fly 方法上,表示子类的 fly 方法时重写了父类的 fly
        // 2. 这里如果没有写 @Override 还是重写了父类 fly
        // 3. 如果你写了@Override 注解,编译器就会去检查该方法是否真的重写了父类的
        // 方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
        // 4. 看看 @Override 的定义
        // 解读: 如果发现 @interface 表示一个 注解类
        /*
         @Target(ElementType.METHOD)
         @Retention(RetentionPolicy.SOURCE)
         public @interface Override { }
        */
        @Override //说明
        public void fly() {
            System.out.println("Son fly....");
        }
        @Override public void say() {

        }
}
  1. @Deprecated 注解的案例

    @Deprecated: 用于表示某个程序元素(类, 方法等)已过时代码

在这里插入图片描述

在这里插入图片描述

代码演示:

public class Deprecated_ {
    public static void main(String[] args) {
        A a = new A();
        a.hi();
        System.out.println(a.n1);
    }
}
    //老韩解读
// 1. @Deprecated 修饰某个元素, 表示该元素已经过时
// 2. 即不在推荐使用,但是仍然可以使用
// 3. 查看 @Deprecated 注解类的源码
//4. 可以修饰方法,类,字段, 包, 参数 等等
// 5. @Deprecated 可以做版本升级过渡使用
/*
@Documented @Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated { }
*/
    @Deprecated
    class A {
        @Deprecated
        public int n1 = 10;
        @Deprecated
        public void hi(){

        }
    }
  1. @SuppressWarnings 注解的案例

@SuppressWarnings: 抑制编译器警告

在这里插入图片描述

代码演示:

public class SuppressWarnings_ {
    //当我们不希望看到这些警告的时候,可以使用 SuppressWarnings 注解来抑制警告信息
    // 2. 在{""} 中,可以写入你希望抑制(不显示)警告信息
    //3. 可以指定的警告类型有很多
    //4. 关于 SuppressWarnings 作用范围是和你放置的位置相关
// 比如 @SuppressWarnings 放置在 main 方法,那么抑制警告的范围就是 main
// 通常我们可以放置具体的语句, 方法, 类.
// 5. 看看 @SuppressWarnings 源码
// (1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
// (2) 该注解类有数组 String[] values() 设置一个数组比如 {"rawtypes", "unchecked", "unused"} /*
    
    @SuppressWarnings({"all"})
    //@SuppressWarnings({"rawtypes", "unchecked", "unused"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
    }
}

.3.1可以指定的警告类型有:

 可以指定的警告类型有:
// all,抑制所有警告
// boxing,抑制与封装/拆装作业相关的警告
//cast,抑制与强制转型作业相关的警告
//dep-ann,抑制与淘汰注释相关的警告
//deprecation,抑制与淘汰的相关警告
//fallthrough,抑制与 switch 陈述式中遗漏 break 相关的警告
//finally,抑制与未传回 finally 区块相关的警告
//hiding,抑制与隐藏变数的区域变数相关的警告
//incomplete-switch,抑制与 switch 陈述式(enum case)中遗漏项目相关的警告
//javadoc,抑制与 javadoc 相关的警告
//nls,抑制与非 nls 字串文字相关的警告
//null,抑制与空值分析相关的警告
//rawtypes,抑制与使用 raw 类型相关的警告
//resource,抑制与使用 Closeable 类型的资源相关的警告
//restriction,抑制与使用不建议或禁止参照相关的警告
//serial,抑制与可序列化的类别遗漏 serialVersionUID 栏位相关的警告
//static-access,抑制与静态存取不正确相关的警告
//static-method,抑制与可能宣告为 static 的方法相关的警告
//super,抑制与置换方法相关但不含 super 呼叫的警告
//synthetic-access,抑制与内部类别的存取未最佳化相关的警告
//sync-override,抑制因为置换同步方法而遗漏同步化的警告
//unchecked,抑制与未检查的作业相关的警告
//unqualified-field-access,抑制与栏位存取不合格相关的警告
//unused,抑制与未用的程式码及停用的程式码相关的警告

2.4JDK 的元 Annotation(元注解, 了解)

JDK 的元 Annotation 用于修饰其他 Annotation

元注解: 本身作用不大,看源码时,可以知道他是干什么.

2.4.1元注解的种类
  1. Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME

  2. Target // 指定注解可以在哪些地方使用

  3. Documented //指定该注解是否会在 javadoc 体现

  4. Inherited //子类会继承父类注解

@Retention 注解

只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy

类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值:

@Retention 的三种值

  1. RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释

  2. RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认 值

  3. RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以 通过反射获取该注解

在这里插入图片描述

@Target

在这里插入图片描述

@Documented

在这里插入图片描述

@Inherited 注解
在这里插入图片描述

3.面向对象(高级)练习题回顾

  1. 写出结果

在这里插入图片描述

public class HomeWork01 {
    public static void main(String[] args) {
        Car car = new Car();
        Car car1 = new Car(100);
        System.out.println(car);
        System.out.println(car1);
    }
}
class Car{
    double price = 10;
    static String color = "white";
    public String toString(){
        return price + color;
    }
public Car (){
        this.price = 9;
        this.color = "red";
}
    public Car(double price) {
        this.price = price;
    }
}

在这里插入图片描述

public class HomeWork02 {
    public static void main(String[] args) {
        Frock frock1 = new Frock(); //100100
        Frock frock2 = new Frock(); //100200
        Frock frock3 = new Frock(); //100300
    }

}
class Frock{
    private static int currentNum = 100000;
    private int seriaNumber;
    public static int getCurrentNum(){
        currentNum +=100;
        return currentNum;
    }

    public static void getCurrentNum(int currentNum) {
        Frock.currentNum = currentNum;
    }

    public void setSeriaNumber(int seriaNumber) {
        this.seriaNumber = seriaNumber;
    }

    public Frock() {
        this.seriaNumber = getCurrentNum();
        System.out.println(this.seriaNumber);
    }
}

在这里插入图片描述

public class HomeWork03 {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        dog.shout();
        cat.shout();
    }
}
abstract class Animal{
    abstract void shout();
}
class Dog extends Animal{
    @Override
    void shout() {
        System.out.println("旺旺");
    }
}
class Cat extends Animal{
    @Override
    void shout() {
        System.out.println("喵喵");
    }
}
  1. 匿名内部类题

在这里插入图片描述

public class HomeWork04 {
    public static void main(String[] args) {
        CellPhone cellPhone = new CellPhone();
        /*
        new Calculator() {
            @Override
            public double work(double n1, double n2) {
                return (n1 + n2);
            }
        },10,8   同时也是一个对象
        他的编译类型 Calculator, 他的运行类型是 匿名内部类;
         */
        cellPhone.testWork(new Calculator() {
            @Override
            public double work(double n1, double n2) {
                return (n1 + n2);
            }
        },10,8);
    }
}

interface Calculator{
    double work( double n1 , double n2);
}
class CellPhone{
    //1.解读,当我们调用testWork方法时,直接传入一个实现了 Calculator接口的匿名内部类即可;
    //2.该匿名内部类,可以灵活的实现work,完成不同的计算任务
    public void testWork(Calculator calculator ,double n1 ,double n2){
        double result = calculator.work(n1 ,n2);//动态绑定
        System.out.println("最后的结果是" + result);

    }
}

内部类基础薄弱,自主补充练习

//成员内部类
public class InnerClassTest01 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.fun();
    }
}
class Outer{
    private String name = "外部属性";

    //定义一个内部类(成员内部类)
    class Inner{
        private String name = "内部类属性";
        public void print(){
            System.out.println(Outer.this.name);
            //这里遵守就近原则,当内部类和外部内属性变量名相同时,需要用外部类名.this.变量名调用
        }
    }

    public void fun(){
        Inner inner = new Inner();
        inner.print();
    }
     //在外部类内部(静态方法内)创建成员内部类对象
    public static void f(){
        Outer13.Inner inner = new Outer13().new Inner();
    }
}
//成员内部类实现多继承
public class InnerClassTest02 {
    public static void main(String[] args) {
        Outer12 outer1 = new Outer12();
        System.out.println(outer1.name2());
        System.out.println(outer1.age());
    }
}
class A1{
    private String a1 = "A1的私有属性";

    public String getA1() {
        return a1;
    }
}
class B1{
    private int age1 = 20;

    public int getAge() {
        return age1;
    }
}
class Outer12 {
    @SuppressWarnings("all")//抑制警告
    private class InnerClassA extends A1{
        @Override
        public String getA1() {
            return super.getA1();
        }
    }
    private class InnerClassB extends B1{
        @Override
        public int getAge() {
            return super.getAge();
        }
    }
    public String name2(){
        InnerClassA innerClassA = new InnerClassA();
        return innerClassA.getA1();
    }
    public int age(){
        return new InnerClassB().getAge();
    }
}
//局部内部类
public class InnerClassTest03 {
    public static void main(String[] args) {
        Outer14 outer14 = new Outer14();
        outer14.display();
    }
}
class Outer14{
    private int age = 5;
    public void display(){
        //方法(局部)内部类嵌套在方法里面
        class Inner{
            public void fun(){
                System.out.println(age);
            }
        }
        Inner inner = new Inner();
        inner.fun();
    }
    
}
//匿名内部类
public class InnerClassTest04 {
    public static void main(String[] args) {
        Outer15 outer15 = new Outer15();
        outer15.display(3);
    }
}

interface MyInterface {//接口

    //接口方法中没有方法体
    void test();
}

class Outer15 {
    private int num = 5;
    public void display(int temp){

        new MyInterface(){

            @Override
            public void test() {
                System.out.println("匿名内部类实现了MyInterface接口");
                System.out.println(temp);
            }
        }.test();
    }
}

在这里插入图片描述

public class HomeWork05 {
    public static void main(String[] args) {
        A a = new A();
        a.f1();
    }
}
class A{
    private String name = "小刚";
    public  void f1(){
        class B{
            private final String NAME = "小名";
            public void show(){
                System.out.println(NAME);
                System.out.println(A.this.name);//内部类和外部类属性重名的情况下
            }
        }
        B b = new B();
        b.show();
    }
}

6.在这里插入图片描述

public class HomeWork06 {
        public static void main(String[] args) {
           Person person = new Person("唐僧",new Horse());
           person.common();//骑马
           person.passRiver();//坐船
           person.passHireHill();// 飞机
        }
    }
/*1.有一个交通工具接口类Vehicles,有work接口
        2.有Horse类和Boat类分别实现Vehicles
        3.创建交通工具工厂类,有两个方法分别获得交通工具Horse和Boat
        4.有Person类,有name和Vehicles属性,在构造器中为两个属性赋值
        5.实例化Person对像“唐僧”,要求一般情况下用Horse作为交通工具,遇到大河时用Boa作为交通工具
        6.增加一个情况,如果唐僧过火焰山,使用 飞机 ==>程序扩展性,我们前面的程序非常号扩展
 */
public interface Vehicles {//接口  工具
    //抽象方法
    public abstract void work();
}
public class Factory {
    //马始终是同一匹马
    private static Horse horse = new Horse();//饿汉式
    //把构造器私有化,不让创建对象
    private Factory(){}
    //这里我们将方法 做成static
    public static Horse getHorse(){
//        return new Horse();
        return horse;
    }
    public static Boat getBoat(){
        return new Boat();
    }
    public static Plane getPlane(){
        return new Plane();
    }
}
public class Horse implements Vehicles{
    @Override
    public void work() {
        System.out.println("骑马");
    }
}
public class Plane implements Vehicles{
    @Override
    public void work() {
        System.out.println("飞机");
    }
}
class Boat implements Vehicles {
    @Override
    public void work() {
        System.out.println("坐船");
    }
}
public class Person {
    //4.有Person类,有name和Vehicles属性,在构造器中为两个属性赋值
    private String name;
    private Vehicles vehicles;
    //在创建人对象时,会给他分配一个交通工具
    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;

    }
    //5.实例化Person对像“唐僧”,要求一般情况下用Horse作为交通工具,遇到大河时用Boat作为交通工具
    //这里涉及到一个编程思想,就是可以把具体的要求,封装成方法->这就是编程思想

    public void passRiver(){//过河
        //先得到船
        //判断一下,当前的 vehicles 属性是null,就获取一艘船
//        Boat boat = Factory.getBoat();
//        boat.work();
        //如何防止始终使用的是传入的马,instanceOf
        //if (vehicles == null){ 更改前只是判断是否为NULL
        //vehicles instanceof Boat 是判断当前的 vehicles是不是Boat或者空
        // (1)vehicles ==null (vehicles instanceof Boat)->false 取反
        //(2)vehicles == 马对象  (vehicles instanceof Boat)->false 取反
        //(3)vehicles == 船对象 (vehicles instanceof Boat)->true 取反
        if (!(vehicles instanceof Boat)){
            //这里使用了多态
            vehicles = Factory.getBoat();
        }
        //这里体现了接口的调用
        vehicles.work();
    }

    public void common(){//通常情况
        //得到马🐎
        //判断一下,当前的 vehicles 属性不是马,就获取一匹马
        if(!(vehicles instanceof Boat)){
            //这里使用了多态
            vehicles = Factory.getHorse();
        }
        //这里体现了接口的调用
        vehicles.work();
    }
    public void passHireHill(){//通常情况
        //飞机
        //判断一下,当前的 vehicles 属性不是飞机,就获取一匹飞机
        if(!(vehicles instanceof Plane)){
            //这里使用了多态
            vehicles = Factory.getPlane();
        }
        //这里体现了接口的调用
        vehicles.work();
    }
}
  1. 在这里插入图片描述
public class HomeWork07 {
    /*
    内部类练习
有一个Car类,有属性temperature(温度),车内有Air(空调)类,有吹风的功能flow,
A会监视车内的温度,如果温度超过40度则吹冷气。如果温度低于0度则吹暖气,如果在这之
间则关掉空调。实例化具有不同温度的Ca对象,调用空调的flow方法,测试空调吹的风是否
正确。//体现类与类的包含关系的案例类(内部类【成员内部类】)
     */
    public static void main(String[] args) {
        //两种方法,第一种比较好
        Car car = new Car(50);
        car.getAir().flow(); //大于40吹冷气

        Car car1 = new Car();
        car1.carFLow(-5); //小于0吹暖气

        car1.carFLow(26);//正常温度,关掉空调
    }
}
public class Car {
    private double temperature;

    public Car() {
    }

    public Car(double temperature) {
        this.temperature = temperature;
    }

    class Air{
        public void flow(){
            if (temperature > 40.0){
                System.out.println("大于40吹冷气");
            }else if(temperature < 0){
                System.out.println("小于0吹暖气");
            }else {
                System.out.println("正常温度,关掉空调");
            }
        }
    }
    public Air getAir(){
        return new Air();
    }
    public void carFLow( double temperature){
        this.temperature = temperature;
        Air air = new Air();
        air.flow();
    }

}
  1. 在这里插入图片描述
public class HemoWork08 {
    public static void main(String[] args) {
        Color green = Color.GREEN;
        green.show();
        //比较一下
        //switch()中,放入枚举值
        //在每个case后,直接写上在枚举类中,定义的枚举类对象即可
        switch (green){
            case RED:
                System.out.println("匹配到红色");
                break;
            case BLUE:
                System.out.println("匹配到蓝色");
                break;
            case BLACK:
                System.out.println("匹配到黑色");
                break;
            case GREEN:
                System.out.println("匹配到绿色");
                break;
            case YELLOW:
                System.out.println("匹配到黄色");
                break;
            default:
                System.out.println("没匹配到");
        }
    }
}
public enum Color implements IColor{
     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 blueValue;
    private int greenValue;

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

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

}
interface IColor{
    public void show();
}

4.异常(Ctrl+Alt+T)

4.1异常介绍

4.1.1异常捕获

在这里插入图片描述

public class Exception01 {
    public static void main(String[] args) {
            int num1 = 10;
            int num2 = 0;
            //int result = num1/num2; //程序就会出现(抛出)异常 ArithmeticException
        //1.如果程序员,认为一段代码可能出现异常/问题,可以使用 try-catch 异常处理机制来解决
        //2.从而保证程序的健壮性 //将该代码块->选中->快捷键 ctrl + alt + t -> 选中 try-catch
        //3. 如果进行异常处理,那么即使出现了异常,程序可以继续执行
        try {
            int result = num1/num2;
        } catch (Exception e) {
            //e.printStackTrace();
            System.out.println("出现异常的原因是:" + e.getMessage());//输出异常信息
        }
        System.out.println("程序继续执行");
    }
}
4.1.2异常介绍

1. 基本概念

​ Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法
错误和逻辑错误不是异常)

执行过程中所发生的异常事件可分为两大类

  1. Error(错误)Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源
    耗尽等严重情况。比如:StackOverflowError【栈溢出】和OOM(out of
    memory),Error是严重错误,程序会崩溃。

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

2. 异常体系图

3. 异常体系图的小结

  1. 异常分为两大类,运行时异常编译时异常
  2. 运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常
  3. 对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响
  4. 编译时异常,是编译器要求必须处置的异常。
4.1.3常见的运行时异常
  1. NullPointerException:空指针异常

  2. ArithmeticException:数学运算异常

  3. ArrayIndexOutOfBoundsException:数组下标越界异常

  4. ClassCastException:类型转换异常

  5. NumberFormatException:数字格式不正确异常[]

  6. NullPointerException 空指针异常 NullPointerException_.java 当应用程序试图在需要对象的地方使用 null 时,抛出该异常,看案例演示

public class NullPointerException_ {
    public static void main(String[] args) {
        String name = null;
        System.out.println(name.length());
    }
}

在这里插入图片描述

2. ArithmeticException数学运算异常 ArithmeticException_.java

当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例,

3. ArrayIndexOutOfBoundsException 数组下标越界异常

用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引

public class ArrayIndexOutOfBoundsException_ {
    public static void main(String[] args) {
        int[] nums ={1,2,3};
        for (int i = 0; i < 4; i++) {
            System.out.println(nums[i]);
        }
    }
}

在这里插入图片描述

4.ClassCastException 类型转换异常

当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,以下代码将生成一个 ClassCastException

public class ClassCastException_ {
    public static void main(String[] args) {
        A b = new B(); //向上转型
        B b2 = (B)b; //向下转型,这里是ok
        C c = (C)b; //这里抛出ClassCastException
    }
}
class A{}
class B extends A{}
class C extends A{}

在这里插入图片描述

5**.NumberFormatException** 数字格式不正确异常

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 => 使用异常我们

可以确保输入是满足条件数字.

public class NumberFormatException_ {
    public static void main(String[] args) {
        //String name = "123";
        //int num = Integer.parseInt(name);//123
        String name = "覃波";
        int num = Integer.parseInt(name);//异常 NumberFormatException
    }
}

在这里插入图片描述

4.1.4编译时异常

在这里插入图片描述

代码演示:

public class Exception02 { 

public static void main(String[] args) { 

try { 

FileInputStream fis; 

fis = new FileInputStream("d:\\aa.jpg"); 

int len; 

while ((len = fis.read()) != -1) { 

System.out.println(len); 

	}

fis.close(); 

} catch (IOException e) { 

e.printStackTrace(); 
		} 

	} 

}

异常练习

在这里插入图片描述

4.2异常处理

4.2.1基本介绍

异常处理就是当异常发生时,对异常处理的方式。

4.2.2异常处理的方式
  1. try-catch-finally

    程序员在代码中捕获发生的异常,自行处理

  2. throw

    将发生的异常抛出,交给调用者处理,最顶级的处理者就时JVM

4.2.3示意图
try{

  //代码可能有异常

}catchException e){

//捕获到异常

//1.当异常发生时

//2.系统将异常封装成Exception对象 e,传递给catch

//3.得到异常对象后,程序员,自己处理

//4.注意:如果没有发生异常catch代码块不执行

}finally{

//1.不管try代码块是否有异常发生,始终要执行finally

//2.所以,通常将释放资源的代码,放在finally。

}

异常发生时:

在这里插入图片描述

4.2.4 try-catch 方式处理异常-注意事项
  1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块
  2. 如果异常没有发生,则顺序执行try的代码块,不会进入到catch代码块
  3. 如果希望不管异常发布发生,都执行某段代码(比如关闭连接,释放资源等)则使用如下代码-finally
public class TryCatchDetail {
    public static void main(String[] args) {
        //ctrl+alt+t
        //1.如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块
        //2.如果异常没有发生,则顺序执行try的代码块,不会进入到catch代码块
        //3.如果希望不管异常发布发生,都执行某段代码(比如关闭连接,释放资源等)则使用如下代码-finally
        try {
            String str = "韩顺平";
            int a = Integer.parseInt(str);
            System.out.println("数字a" + a);
        } catch (NumberFormatException e) {
            System.out.println("异常信息:" + e.getMessage());
        }finally {
            System.out.println("finally代码执行");
        }
        System.out.println("继续执行");
    }
}

在这里插入图片描述

  1. 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常,只会匹配一个catch,案例演示
public class TryCatchDetail02 {
    //4.可以有多个catch语句,捕获不同的异常(进行不同的业务处理),
    //要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),
    //如果发生异常,只会匹配一个catch,案例演示
    public static void main(String[] args) {
        try {
            Person person = new Person();
            person = null;
            System.out.println(person.getName());//NullPointerException
            int n1 = 10;
            int n2 = 0;
            int num = n1 / n2;//ArithmeticException
        } 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("finally");
        }
    }
}

class Person {
    private String name = "覃波";

    public String getName() {
        return name;
    }

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

在这里插入图片描述

  1. 可以进行 try-finally 配合使用, 这种用法相当于没有捕获异常,因此程序会直接崩掉/退出。应用场景,就是执行一段代码,不管是否发生异常, 都必须执行某个业务逻辑。
public class TryCatchDetail03 {
    /*可以进行 try-finally 配合使用, 这种用法相当于没有捕获异常,
     因此程序会直接崩掉/退出。应用场景,就是执行一段代码,
     不管是否发生异常, 都必须执行某个业务逻辑 */
    public static void main(String[] args) {
        try {
            int n1 = 10;
            int n2 = 0;
            int sum = n1 / n2;
        }finally {
            System.out.println("finally执行了");
        }
        System.out.println("程序继续执行");
    }
}

在这里插入图片描述

4.2.5 异常处理课堂练习
  1. 输出什么?
//输出什么?
public class TryCatchExercise01 {
    public static void main(String[] args) {
        System.out.println(method());
    }
    public static int method(){
        try {
            String[] names = new String[3];
            if (names[1].equals("tom")){
                System.out.println(names[1]);
            }else {
                names[3] = "qinBo";
            }
            return 1;
        }catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        }catch (NullPointerException e){
            return 3;
        }finally {
            return 4;
        }
    }
}

在这里插入图片描述

  1. 输出什么?
public class TryCatchExercise02 {
    public static void main(String[] args) {
        System.out.println(method());
    }

    public static int method() {
        int i = 1;
        try {
            i++;//2
            String[] names = new String[3];
            if (names[i].equals("tom")) {
                System.out.println(names[1]);
            } else {
                names[3] = "qinBo";
            }
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        } catch (NullPointerException e) {
            return ++i;//3
        } finally {
            return ++i;//4
        }
    }
}

在这里插入图片描述

public class TryCatchExercise03 {
    public static void main(String[] args) {
        System.out.println(method());
    }

    public static int method() {
        int i = 1;
        try {
            i++;//2
            String[] names = new String[3];
            if (names[i].equals("tom")) {
                System.out.println(names[1]);
            } else {
                names[3] = "qinBo";
            }
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        } catch (NullPointerException e) {
            return ++i;//i = 3 ->保存临时变量 temp = 3  ②
        } finally {
            ++i;//i = 4
            System.out.println("i=" +i);//i = 4  ①
        }
    }
}

在这里插入图片描述
在这里插入图片描述

  1. 如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
public class TryCatchExercise04 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int num = 0;
        String inputStr = "";
       while (true){
           System.out.println("请输入一个整数");
           inputStr = scanner.next();
           try {
               num = Integer.parseInt(inputStr);//这里可能抛出异常
               break;
           } catch (NumberFormatException e) {
               System.out.println("输入的不是一个整数");
           }
       }
        System.out.println("你输的是:" + num);
    }
}

在这里插入图片描述

4.2.6Throw异常处理
  1. 基本介绍

在这里插入图片描述

public class ThrowsDetail01 {
    public static void main(String[] args) {

    }
   public void f2() throws Exception {
        //创建了一个文件流对象
       //1.这里的异常是一个 FilerNotFoundException 编译异常
       //2.使用前面讲过的 try-catch-finally
       //3.使用throw,抛出异常,让调用f2方法的调用者(方法)去处理
       //4.throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
       //5.throw 关键字后,也可以是异常列表,即可以抛出多个异常。
       FileInputStream fileInputStream = new FileInputStream("d://aa.txt");
   }
}
  1. 注意事项和细节

  2. 对于编译异常,程序中必须处理,比如try-catch 或者 throws

  3. 对于运行时异常,程序中如果没有处理,默认的就是throw处理方式

  4. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型

  5. 在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws

public class ThrowsDetail02 {
    public static void main(String[] args) throws Exception {
        f1();
    }
	//①
    public static void f1()/* throws Exception*/ {
        //1.对于编译异常,程序中必须处理,比如try-catch 或者 throws
        //2.对于运行时异常,程序中如果没有处理,默认的就是throw处理方式

        int n1 = 10;
        int n2 = 0;
        double num = n1 / n2;
    }
    
    //补充②
    public static void f2(){
        //调用f3()报错
        //解读
        //因为f3()方法抛出的是一个编译异常
        //f2调用这个异常,就要在f2()处理这个编译异常
        //f2()可以抛出throw处理也可以try-catch处理
        try {
            f3();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //③
         public static void f4(){
        //在f4()调用了f5()方法是可以的
        //因为 f5();抛出的是运行异常 而java中,并不要求程序员显示处理这个异常,因为有默认的处理机制
        f5();
    }
    public static void f5() throws ArithmeticException{

    }
    }
    public static void f3() throws FileNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("d://aa.txt");
    }
}
//3.子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要
//么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
//4在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws
class Father {
    public void method() throws RuntimeException {

    }
}

class Son extends Father {
    @Override
    public void method() throws NullPointerException {

    }
4.2.7 自定义异常
  1. 基本概念

当程序中出现了某些"错误”,但该错误信息并没有在Throwable子类中描
述处理,这个时候可以自己设计异常类,用于描述该错误信息。

  1. 自定义异常步骤

    1)定义类:自定义异常类名(程序员自己写)继承Exception?或RuntimeException
    2)如果继承Exception,属于编译异常
    3)如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)

代码演示:

public class CustomException01 {
    public static void main(String[] args) /*throws Exception */{
        int age = 17;
        if (!(age<120 && age>18)){
            throw new AgeException("年龄须在18-120之间");
        }
        System.out.println("你的年龄范围正确");
    }
}
//自定义一个异常
//1.一般情况下,我们自定义异常是继承RuntimeException
//2.即把自定义异常 做成 运行时异常 好处是我们可以使用默认的处理机制
class AgeException extends RuntimeException{
    public AgeException(String message) {//构造器
        super(message);
    }
}

在这里插入图片描述

4.2.8 throwthrows 的区别

在这里插入图片描述

练习题:

在这里插入图片描述

在这里插入图片描述

4.2.9本章作业题
public class HomeWork01 {
    public static void main(String[] args) {
//输出时进行配置初始化
        //先验证接受到的参数个数是否正确 两个参数
        try {
            if (args.length != 2){
                throw new ArrayIndexOutOfBoundsException("参数个数不对");//可能抛出参数不对 ArrayIndexOutOfBoundsException
            }
                int n1 = Integer.parseInt(args[0]);
                int n2 = Integer.parseInt(args[1]);//可能抛出 类型转换错误 NumberFormatException

                double res = EcmDef.cal(n1,n2);//该方法可能抛出 数字格式错误 ArithmeticException
            System.out.println("计算结果是:" + res);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e.getMessage());
        }catch (NumberFormatException e){
            System.out.println("参数格式不正确" +e.getMessage());
        }catch (ArithmeticException e){
            System.out.println("传入参数格式不对" + e.getMessage());
        }

    }
}

class EcmDef {

    public static double cal(int n1, int n2)  {

        return n1/n2;
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
我亦无他,惟手熟尔

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

别来无恙blwy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值