Java笔记 枚举类 在设计一个季节对象的时候,我们可以用传统的方式实现
1 2 3 4 5 6 7 8 9 10 11 12 public class Enumeration { Season season = new Season ("春天" , "温暖" ); } class Season { private String season; private String description; Season(String season, String description) { this .season = season; this .description = description; } }
但是众所周知,季节只有四季,不能体现只有四个这个特征,为了解决这个问题,我们可以使用枚举类来定义季节,设计几个有限的值
枚举定义 是一组常量的集合:枚举是一种特殊的类,里面只包含一组有限的特定对象
自定义枚举
1.不需要提供set方法,因为枚举对象通常是只读的
2.写枚举对象/属性的使用一般用final + static 修饰
3.枚举对象名通常用大写来命名,常量的命名规范
4.枚举对象根据需要也可以拥有多个属性
使用方式1 1.私有化构造器,防止直接new
2.删去set方法,防止属性修改
3.在Season内部直接创建固定对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Enumeration { Season season = Season.SPRING; } class Season { private String season; private String description; public static final Season SPRING = new Season ("春天" , "温暖" ); public static final Season SUMMER = new Season ("夏天" , "炎热" ); public static final Season AUTUMN = new Season ("秋天" , "凉爽" ); public static final Season WINTER = new Season ("冬天" , "寒冷" ); private Season (String season, String description) { this .season = season; this .description = description; } }
使用方式2 使用关键字enum
使用细节
1.要将枚举对象放在枚举类的行首
2.常量之间用“,”间隔
3.常量通过构造器构造,必须知道用哪一个构造器
4.使用无参构造器的时候可以省略形参列表和小括号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Enumeration { Season season = Season.SPRING; } enum Season { SPRING("春天" , "温暖" ), SUMMER("夏天" , "炎热" ), AUTUMN("秋天" , "凉爽" ), WINTER("冬天" , "寒冷" ); private String season; private String description; private Season (String season, String description) { this .season = season; this .description = description; } }
5.当使用enum关键字开发一个枚举类的时候,默认继承了Enum类
这里可以运用反编译来进行证明
1 2 3 4 5 6 7 8 9 10 11 PS C:\Users\71460 \Desktop\Java\IDEA\chapter11\out\production\chapter11\com\enum_> javap Season.class Compiled from "Enumeration.java" final class com.enum_.Season extends java.lang.Enum<com.enum_.Season> { public static final com.enum_.Season SPRING; public static final com.enum_.Season SUMMER; public static final com.enum_.Season AUTUMN; public static final com.enum_.Season WINTER; public static com.enum_.Season[] values(); public static com.enum_.Season valueOf(java.lang.String); static {}; }
Enum类 关键enum字修饰的类隐式的继承了Enum类,这个类中有一些常用的方法
挨个解释有点麻烦,这里直接上代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Enumeration { public static void main (String[] args) { Season season = Season.WINTER; System.out.println(season.toString()); System.out.println(season.name()); System.out.println(season.ordinal()); for (Season s : Season.values()) { System.out.println(s.toString()); } Season season2 = Season.valueOf("SPRING" ); System.out.println(season2.compareTo(season)); } } enum Season { SPRING("春天" , "温暖" ), SUMMER("夏天" , "炎热" ), AUTUMN("秋天" , "凉爽" ), WINTER("冬天" , "寒冷" ); private String season; private String description; private Season (String season, String description) { this .season = season; this .description = description; } }
Enum使用细节
1.enum不可以继承其他类,因为已经继承了Enum父类
2.枚举类和普通类一样可以实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class Homework { public static void main (String[] args) { Week week = Week.TUESDAY; week.doSomething(); } } interface Doing { void doSomething () ; } enum Week implements Doing { MONDAY("星期一" ), TUESDAY("星期二" ), WEDNESDAY("星期三" ); private String name; private Week (String name) { this .name = name; } @Override public void doSomething () { System.out.println(name); } @Override public String toString () { return name; } }
注解 定义 注解(Annotation)也被称为元数据(Metadata)
1.用于修饰包,类,方法,属性,构造器,局部变量的数据信息
2.和注释一样,注解不影响程序逻辑,但是注解可以被编译运行,相当于嵌入在代码中的补充信息
3.在JavaSE中,注解使用的目的比较简单,例如标记过过时的功能,忽略警告等
4.在JavaEE中注解占据了更加重要的角色,例如配置应用程序的任何切面,代替JavaEE旧版中所遗留的,繁冗代码和XML配置等
三个基本的Annotation @Override 限定某个方法,是重写父类方法,该注解只可以用于方法
源码中的override注解说明,其中@target是注解注解的注解
1 2 3 4 @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override {}
加上了这个注解,编译器会检查子类是否重写父类方法,如果没有重写会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Father { public Father () {} public void Print () { System.out.println("Father" ); } } class Child extends Father { public Child () {} @Override public void Print () { System.out.println("Child" ); } }
@Deprecated 可以做版本过渡使用(保证了兼容性)
用于表示某个程序元素(类,方法等)已过时,可以修饰方法,字段,包,参数,类,局部变量,类型等
1 2 3 4 5 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated {}
在以下代码中表示Child类以及过时,但是还是可以使用,只是不建议使用
1 2 3 4 5 6 7 8 @Deprecated class Child extends Father { public Child () {} @Override public void Print () { System.out.println("Child" ); } }
@SuppressWarnings 抑制编译器警告
1 2 3 4 5 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
在编写代码的时候,往往会出现一些黄色的线条勾选部分代码,如果在合理的范围中你不想见到这一些警告,你可以使用@SuppressWarnings不显示一些警告信息
1 2 3 4 5 6 7 8 9 public class Main { public static void main (String[] args) { List list = new ArrayList (); list.add("her" ); list.add("he" ); list.add("it" ); System.out.println(list.get(0 )); } }
以下是使用方式
1 2 3 4 5 6 7 8 9 10 public class Main { @SuppressWarnings({"all"}) public static void main (String[] args) { List list = new ArrayList (); list.add("her" ); list.add("he" ); list.add("it" ); System.out.println(list.get(0 )); } }
在{ }中填入对应需要忽略的警告信息,有点类似字符串数组的静态创建(其实本质就是一个字符串数组,可以查看jdk源码验证)
另外该注解的作用范围和注解的位置有关,像如上代码中抑制的范围是main方法中,或者更大的范围可以放在类上
JDK中的元注解 修饰注解的注解,再查看注解源码的时候可以用元注解了解注解相应作用即可
@Retention注解的作用范围
@Target使用位置
@Documented 是否在javadoc中体现
@inherited 子类会继承父类注解(使用较少)
以下是一个例子
1 2 3 4 5 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated {}
异常 概念 异常的概念 在Java中,将程序执行过程中发生的不正常情况称为异常
分为两大类:Error错误以及Exception
Error: Java 虚拟机无法解决的严重问题例如JVM系统内部错误,资源溢出
Exception:由于编程错误或者偶然的外在因素导致的一般性问题,可以使用针对性地代码进行处理,异常又分为两大类,一种是编译时异常,另一种是运行时异常。
异常体系图 异常中又分为编译时异常(javac),运行时异常(java)
异常处理概念 如果程序员认为代码会出现异常,可以使用try-catch异常处理机制来解决
在程序运行的过程中有可能会发送各种异常,而发生程序异常的时候,程序往往发成崩溃
1 2 3 4 5 6 7 8 public class Exception01 { public static void main (String[] args) { int num1 = 10 ; int num2 = 0 ; System.out.println(num1 / num2); System.out.println("程序运行完毕" ); } }
这一段代码不会输出最后运行完毕的提示消息,在写程序的时候不应该因为一个微小地异常而导致整个程序崩溃,我们可以通过运用异常处理机制来解决这个问题
用ctrl alt + t -> 选中try-catch,如果异常处理,即使出现异常程序也可以正常执行
1 2 3 4 5 6 7 8 9 10 11 12 public class Exception01 { public static void main (String[] args) { int num1 = 10 ; int num2 = 0 ; try { System.out.println(num1 / num2); } catch (Exception e) { System.out.println("异常被捕获" ); } System.out.println("程序运行完毕" ); } }
输出结果
常见的异常 运行时异常 空指针异常 NullPointerExceprion
1 2 3 4 5 6 7 8 9 10 public class Exception01 { public static void main (String[] args) { String name = null ; try { name.toString(); } catch (NullPointerException e) { System.out.println("异常被捕获" ); } System.out.println("程序运行完毕" ); }
算数异常 ArithmeticException
1 2 3 4 5 6 7 8 9 10 11 12 public class Exception01 { public static void main (String[] args) { int num1 = 10 ; int num2 = 0 ; try { System.out.println(num1 / num2); } catch (ArithmeticException e) { System.out.println("异常被捕获" ); } System.out.println("程序运行完毕" ); } }
数组越界访问异常 ArrayIndexOutOfBoundsException
1 2 3 4 5 6 7 8 9 10 11 public class Exception01 { public static void main (String[] args) { int [] arr = {1 , 3 , 4 , 6 , 7 }; try { System.out.println(arr[5 ]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("异常被捕获" ); } System.out.println("程序运行完毕" ); } }
类型转换异常 ClassCastException
解释说明:当将对象试图转换为不是实例的子类的时候会发生该异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Exception01 { public static void main (String[] args) { A a = new B (); B b = (B) a; try { C c = (C) a; } catch (ClassCastException e) { System.out.println("异常被捕获" + e.getMessage()); } System.out.println("程序运行完毕" ); } } class A {} class B extends A {} class C {}
但是这里没有捕获到异常,程序崩溃(暂时未知原因,丢给AI解释说是和开发环境以及缓存有关,后续会查证)
数字格式不正确 NumberFormatException
1 2 3 4 5 6 7 8 9 10 11 public class Exception01 { public static void main (String[] args) { String name = "thrinisty" ; try { int num = Integer.parseInt(name); } catch (NumberFormatException e) { System.out.println("异常被捕获" + e.getMessage()); } System.out.println("程序运行完毕" ); } }
编译时异常 在编译期间就必须要处理的异常,否则代码不通过编译
例如无对应文件异常,数据库异常等,在后续学习文件IO时候会进行补充
处理异常的方式 二选一即可
try-catch-finally 程序员在代码中捕获发送的异常,自行处理
1 2 3 4 5 6 7 8 9 10 try { } catch (Exception e) { } finally { }
使用细节:
1.如果异常发生,则catch中异常后的代码不再执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.npu;public class Exception01 { public static void main (String[] args) { String name = "thrinisty" ; try { int num = Integer.parseInt(name); System.out.println("try 异常之后的代码" ); } catch (NumberFormatException e) { System.out.println("异常被捕获" + e.getMessage()); } finally { } System.out.println("程序运行完毕" ); } }
2.如果没有发生异常,catch代码块不会被执行
3.finally中的内容无论异常是否被接收都会被执行,一般用于释放资源
4.可以有多个catch语句,捕获不同的异常,要求父异常写在后,子异常在前例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.npu;public class Exception01 { public static void main (String[] args) { String name = "thrinisty" ; try { int num = Integer.parseInt(name); System.out.println("try 异常之后的代码" ); } catch (NumberFormatException e) { System.out.println("转换异常被捕获" + e.getMessage()); } catch (Exception e) { System.out.println("异常发生" ); } finally { System.out.println("finally" ); } System.out.println("程序运行完毕" ); } }
5.try-finally配合使用:用于执行一段代码,之后无论异常是否发生,都会执行finally代码块
一个容易出错的题目:
throws 将发生的异常抛出,交给调用者(方法)来进行处理,最顶端的处理者是JVM
假如在代码中没有进行throw显示的处理,而发生了异常,就会默认的抛出异常依次传递直到JVM处理异常,退出程序
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.npu;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.util.Scanner;public class Exception01 { public static void main (String[] args) { try { m1(); } catch (FileNotFoundException e) { System.out.println("File not found" ); } } public static void m1 () throws FileNotFoundException { FileInputStream fis = new FileInputStream ("cd" ); } }
异常交予main函数进行处理,抛出的异常可以是一个列表,对应的异常,异常的父异常
异常使用细节 1.编译异常必须处理
2.对于运行时异常,程序中没有进行处理默认为throws方式处理
3.子类重写父类方法的时候,要么抛出异常的规定,子类重写方法,所抛出的异常类型要和父类抛出的异常一致,要么为父类抛出异常类型的子类型
1 2 3 4 5 6 7 class Father { public void sayHello () throws Exception {} } class Son extends Father { public void sayHello () throws IOException {} }
4.运行异常可以默认处理,但是编译异常必须显示的处理
课堂练习 输入整数,不是整数就继续输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Exception01 { public static void main (String[] args) { Scanner sc = new Scanner (System.in); int num = 0 ; System.out.print("输入一个整数 " ); while (true ) { try { num = Integer.parseInt(sc.nextLine()); break ; } catch (Exception e) { System.out.println("请重新输入..." ); } } System.out.println(num); } }
自定义异常 使用步骤:
1.定义类:自定义异常类名,继承Exception或者RuntimeException
2.继承Exception属于编译异常
3.继承RuntimeException是运行异常
通过throw关键字抛出对应的自定义异常,并运用构造器传入异常信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Exception01 { public static void main (String[] args) { int age = 15 ; try { test(age); } catch (TypeException e){ System.out.println(e.getMessage()); } } public static void test (int age) { if (age < 18 ) { throw new TypeException ("年龄要在18岁以上" ); } } } class TypeException extends RuntimeException { public TypeException (String message) { super (message); } }
throw与throws
到此枚举类,注解,异常处理的部分结束