自定义类实现枚举
引出枚举类。
把对象设置为静态的,因此可以直接用类名访问
我们还可以加一个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