JavaSE学习笔记-07

本文详细讲解了Java中的枚举类实现及优化,包括如何使用enum关键字,枚举类的静态实例和常用方法。同时,文章深入探讨了Java异常处理,包括try-catch-finally语句的执行顺序,异常的分类,自定义异常,以及编译异常与运行异常的区别。此外,还介绍了静态工厂方法在创建对象时的应用,以及内部类和接口的使用。
摘要由CSDN通过智能技术生成

自定义类实现枚举

引出枚举类。

把对象设置为静态的,因此可以直接用类名访问

 我们还可以加一个final做一下优化:

 

enum关键字实现枚举 

 JavaP反编译

 

如果无参构造器没有被覆盖,那么可以省略()

也可以写成如What()一样的形式。

 枚举类课堂练习

 我们知道这里的无参构造器并没有被覆盖,是存在的。由上面的第5点可知,当我们使用的是无参构造器的时候,创建常量对象,则可以省略(),直接写。所以是正确的。。。。

 

打印boy 本质上就是调用枚举类Gender2的父类Enum的toString()方法 查找可知 打印的结果就是返回name,即是BOY

 我们知道静态的对象实例只可以创建一次,因此是True

 enum常用方法

 输出编号

增强for循环

 每一次循环,从values数组中取一个元素给到前面的变量season

 

 执行过程:每一次从nums这个数组取一个数字元素交给左边的i变量,直到数组中元素给出完毕。

 遍历取出每一个枚举对象:

—————————————————————————————————————————— 

 如果找到就返回,如果找不动,那么就报错。

运行结果: 

 

 就是两个编号相减

 如果结果小于0.证明前面的编号小于后边的编号。大于0,证明前面的编号大于后边的编号

 toString方法就是返回这个名字

课堂练习

 顺便把枚举类的所有API方法也总结了一下:(如图代码所示)

枚举类是不可以再继承其他的类了,因为在底层它已经隐式继承了一个类 如图: 

 它可以再实现其他的接口,但是不可以继承其他的类了

 当然一个类可以实现多个接口》》》》》

注解

 

注意一个细节,我们这里重写的方法可能不是直接的父类,可能是爷类等往上。。。

 重写标识符的作用:

 Override的源码定义如图:

 注意:

 如果发现这个符号旧证明是一个注解类:

 元注解:注解的注解

Override的使用说明:

通过源码我们可知,Override只可以在方法上面注解

 @Deprecated

由源码可知,它的作用范围Target是在 各种地方

 结果:

 源码:

@SuppressWarnings

我们可以用这个方式去抑制警告

 看一下idea的提示警告类型去写出警告

unchecked

 unused

 

但是你想要一劳永逸的话,可以直接写一个all,all抑制所有的警告 

————————————————————————————————————

警告作用的范围在这个方法体,一旦出了这个方法便不再作用警告

————————————————————————————————————————

我们还可以放在类上导致全部的抑制

 

源码分析:


 元注解(了解即可)

指定注解的作用范围:

能够确定使用哪一个程序元素

 这个的@Target 包括类 方法  属性

关于内部类的一系列练习

 分析一下这个过程:

首先我们通过Car这个类进行new一个对象实例引用,首先要进行的是类加载,之后才会进行new这个过程。

但是我们要明白一个点就是:进行Car这个类new对象,只可以进行一次Car类的加载,而且我们知道,静态变量的初始化是随着类加载而进行的,所以color这个静态变量只被初始化一次

 每new一次,都会在堆空间上产生一个新的对象,并且要记住字符串是在堆空间上的字符串常量池的。如图所示,我们也易知打印的结果。

 

 

 

 

 

经典案例(注意)

 

 

 源码:

interface 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 spaceship implements Vehicles{
    @Override
    public void work() {
        System.out.println("过火焰山的时候用太空飞船");
    }
}
//1.创建工厂类,返回对象
//2.创建为静态类型,调用方便
class VehiclesFactory{
    /**
     * 唐僧在去西天取经路上,马只有一匹,不可以每一次都new着换
     * 船可以随时换,不可能一直带着,但是马是一直跟着的
     * 所以我们这里采用饿汉设计模式
     */
    private static Horse horse=new Horse();
    private VehiclesFactory(){}//把构造器私有化,防止通过这个构造器去new对象
    public static Horse getHorse(){
        return horse;
    }
   /* public static Horse getHorse(){
        return new Horse();
    }*/
    public static Boat getBoat(){
        return new Boat();
    }
    public static spaceship getspaceship(){
        return new spaceship();
    }
}
class person{
    private String name;
    private Vehicles vehicles;//利用接口类型,多态形式接收交通工具
    public person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }
    /**
     * 要求一般情况下用马儿,遇到大河时用船
     * 重点:把具体的要求封装为方法
     */
    public void passRiver(){
        //先得到船
        //1.vehicles是null 或 是Horse的时候,vehicles instanceof Boat是假,!(假):为真。
        //2.vehicles是Boat时,!(真)->为假
       if(!(vehicles instanceof Boat)){
           vehicles=VehiclesFactory.getBoat();
       }
       vehicles.work();
    }
    //一般情况下使用马儿
    public void common(){
        //如果一开始传进来没有,那么再进行调用一匹马的对象
        if(vehicles==null){
            //体现出多态,向上转型
            vehicles=VehiclesFactory.getHorse();
        }
        //如果传进来有马,那么就不需要再调用一匹马了,直接调用方法即可
        //体现出接口调用
        vehicles.work();
    }
    /**
     * 扩展:唐僧过火焰山
     */
    public void passfiremount(){
        if(!(vehicles instanceof spaceship)){
            vehicles=VehiclesFactory.getspaceship();
        }
        vehicles.work();
    }
}
class MAIN{
    public static void main(String[] args) {
        person person = new person("唐僧",new Horse());
        person.common();//一般情况下骑马
        person.passRiver();//过河是乘船
        person.passfiremount();//过火焰山用太空飞船
    }
}

 

 成员内部类是:外部类之后就包含一个类,这个类包含一个方法

局部内部类则是:外部类之后是一个方法,这个方法包含一个类

 

枚举练习题

 

 异常

其中 breakpoint表示的意思是终止,这个例子是算术异常导致终止。

 例子:

 当我们系统出现了一个算术错误:分母是0,那么直接就报错导致整个程序瘫痪了,那么这是不合理的,所以我们引出了,try catch异常处理机制。。。。。。

 把可能出错的代码选中,然后用 ctrl+alt+t:

 

try表示试一试,看是否出错了,如果出错了那么通过catch捕获这个异常,然后输出这个错误。但是程序是继续执行下去的。 

 也可以直接输出这个异常信息

 

 Error是相对比较严重的错误,Exception则是不太严重的错误。

异常体系图(重点)

在图中:虚线表示实现接口,实线表示的是继承父类。 

如图(异常体系图)

 

 红色表示编译异常,蓝色表示运行异常

 这三个红色异常表示编译时的异常:

 

 

 编译异常:是写好源代码之后,进行javac编译的时候就会发生的异常。

运行异常:是这个class文件运行的时候会出现的异常。

 常见五大运行时异常

 

 

 

向上转型:父类的变量名指向了子类对象实例。(A是父类,B是子类)

向下转型导致的类型转化异常分析

分析下图:

b原来的运行类型就是一个B类型的,所以可以直接强制转化为编译类型和运行类型都是B

但是b原来的运行类型不是C类型的,所以直接强制转化为C类型会导致类型转化异常。

自己再举一个例子:

le的运行类型是le3,所以le可以进行向下转型。当然可以把le强制转化为原来的运行类型le3。

重新给定出一个实例引用 i 使得编译类型和运行类型都是一样的

 编译异常

异常练习题

Object  obj=new Date();表示的意思是向上转型。

类型转化异常:obj这个对象引用并没有指向类Person  new出来的对象

所以不可以强制转化为Person类型 

 

 异常处理

1. 

过程: 

我们用try把可能出现异常的代码块进行包裹起来,当出现异常的时候,把异常封装成一个对象e传递给catch,在catch块中可以随意进行对异常对象e的处理,也可以增加业务逻辑。不管是否出现异常,finally块一定会执行

 2.

不管try代码块是否有异常发生,一定(始终)会执行finally块

 3.

如果无异常,catch不会执行

 throws处理机制图

 当f2方法发现异常的时候,此时有两种解决办法 :

1.throws抛出异常  

2. try-catch-finally 处理

但是它选择抛出,抛出给f1方法。f1执行同理,一层层抛出,直到抛出到JVM,

JVM的处理方式是:输出异常,直接退出程序

如果程序员没有使用try-catch-finally处理异常,那么默认是throws处理异常。

 

 try-catch异常处理:

 1.如果异常发生了,则异常后面的代码不会再执行,直接进入到catch块

 2.如果没有异常发生,那么try块代码执行完之后,catch块代码不再执行

3.

 当我们想对于不同的异常,分类分别的进行捕获的时候

 

 由于异常并没有被捕获,所以程序直接崩溃,执行完finally块中的代码之后直接退出

解释一下:

由于我们没有catch这个捕获异常的措施,所以它默认是一层一层的往上进行抛出异常,一直抛出直到抛出到JVM,JVM处理方式简单粗暴,直接输出异常信息,然后让程序崩溃。如图所示:

try-catch异常处理练习: 

 

分析: 

names[1]是空的, 一开始我们new的时候,没有进行任何的赋值之类的操作。

 names指向一个数组,这个数组为空

 发生异常之后,try块中异常之后的所有代码不再执行,把异常封装成e对象给到catch块,但是呢

finally块是一定要执行的,所以执行return 4;由于这是return返回,那么整个程序直接就结束了,所以结果为4,如果这里不是return,catch块中值不会发生改变。

 

结果为4

 

 分析:

由于这里finally没有直接进行返回,所以应该在catch块进行返回。并且catch中的return 值不发生改变,会把这个值保存到一个临时变量中,当finally执行完之后,再进行返回这个临时保存的值。 

 

 

 throws异常处理

 

其实直接抛出父类类型的异常最好使,一劳永逸:

 

2.

如果没有显示处理异常(即没有try-catch处理) ,那么默认是,一直抛出到JVM。然后直接进行输出错误,之后抛出异常信息,让程序退出。

3.

 4.

编译异常和运行异常的不同之处

 注意:

对于编译异常和运行时异常有所不同:

当出现编译异常的时候,我们必须显示的抛出异常,不可以再感觉它是有默认的抛出功能了,默认的抛出异常的功能是针对于运行时异常而言的。。。。

 编译异常必须处理,没有默认处理,这一点和运行时异常的默认处理有所不同。。。

 如图所示:

运行时异常当我们没有处理的时候,是默认抛出的,这一点和编译异常完全不同

 总结:

1.当出现异常的时候。如果它是编译异常,那么我们必须进行处理,进行throws或try catch方法进行处理一下才可以正常进行。但是如果它是运行异常,那么我们可以不处理,因为它是有默认的throws进行抛出异常处理的,是有默认的处理机制的。当然我们也可以自己抛出异常或者try-catch进行处理。

2.我们抛出的异常是抛出给调用者,调用者一般是方法,一层层往上抛出,直到抛出到JVM,或者在途中被try-catch处理了。如果抛出到JVM,那么就会被直接输出异常信息,并且退出程序。

自定义异常

 总结:

一般情况下,我们自定义异常时的异常也是继承于运行异常,因为运行异常有默认处理机制。如果是继承Exception这个异常的时候会被当作编译异常,那么就没有默认处理机制了,那样就得自己去throws异常了。

因为AgeException是一个编译异常(一般除了运行异常之外的都是编译异常)。所以最好是继承运行异常。 倘若继承Exception时:要自己显示throws(如下图) 。

throw与throws的区别

 

 分析:

从main方法中进行分析,先执行try块中的语句,调用methodA方法。对于这个方法,先执行try块中的语句,然后发现抛出了一个异常。我们知道抛出的异常是抛出给调用者的,因此main方法接收之后,把异常封装为一个e对象给到catch块;但是注意:finally块中的语句优先于catch块中语句输出。同理调用方法methodB。输出顺序易知。

 异常练习

 

 可能给定的参数不够,args[4]可能等于NULL 会出现空指针异常

args[2]为字符串类型,

因此 Object o=args[2]; 【向上转型】编译类型是Object 运行类型是字符串类型

当我们进行向下转型的时候,我们可以把o强制转化为原来运行类型。

但是图中强制转化为Integer类型,就是类型转化异常。。。。。。

B C  D

分析:

我们从main方法开始分析,一开始执行try块,执行方法func,发现try块中直接抛出异常,但是finally块中的代码必须执行,先输出 B 。手动抛出的异常抛给调用它的方法main,一旦发现异常,try块中剩余的代码不再执行。又因为 RuntimeException是Exception的子类,因此catch可以对于这个异常进行捕获,所以打印  C   。我们知道由于这个异常已经被捕获了,所以程序不会直接退出,会继续执行后面的代码  输出打印  D。

故 输出  B C D  

 

输出 B C D 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值