第二十二章注解
1. 注解概述
Java注解又称Java标注,是在 JDK5 时引入的新特性,注解(也被称为元数据)。
Java注解它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
2. 生成文档
生成帮助文档:@author和@version
- @author:用来标识作者姓名。
- @version:用于标识对象的版本号,适用范围:文件、类、方法。
- @Data:创建的时间
- @Description:描述
示例:
使用**@author和@version注解就是告诉Javadoc工具**在生成帮助文档时把作者姓名和版本号也标记在文档中。
使用javadoc工具生成帮助文档:
javadoc -encoding utf-8 -author -version demo.java
D:\Power\javase\24-注解\src\注解>javadoc -encoding utf-8 -author -version demo.java
要和生成文档的java在同一目录下
3. 注解分类
3.1 JDK自带的标准注解
注解名称 | 功能描述 |
---|---|
@Overried | 检查该方法是否是重写方法,如果发现其父类,或者是引用的接口并没有该方法时,会编译报错 |
@Deprecated | 标记过时方法,如果使用该方法,会编译警告 |
@SupperssWarning | 指示编译器去忽略注释中声明的警告 |
@Functionallnterface | java8支持,标志是一个匿名的函数式接口 |
3.1.1 @Override
如果试图使用 @Override 标记一个实际上并没有覆写父类的方法时,java 编译器会告警。
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 14:22
* @Description TODO
*/
public class Demo01 {
public void methodFu(){
System.out.println("methodFu()");
}
}
class Zi extends Demo01{
// 重写父的方法
@Override
public void methodFu() {
System.out.println("Zi()");
}
}
3.1.2 @Deprecated
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 14:25
* @Description TODO
*/
@Deprecated //用于标明被修饰的类或类成员、类方法已经废弃、过时,不建议使用。
public class Demo02 {
@Deprecated
private String name;
@Deprecated
public Demo02(String name) {
this.name = name;
}
}
3.1.3 @SuppressWarnings
@SuppressWarnings 用于关闭对类、方法、成员编译时产生的特定警告。
@SuppressWarnings 注解的常见参数值的简单说明:
参数 | 作用 |
---|---|
deprecation | 关闭了使用了不赞成使用的类或者方法时的警告 |
unchecked | 执行了未检查的转换时的警告,例如当使用集合时没有泛型来指定集合报错的类型 |
fallthrough | 当Switch程序块直接通往下一种情况而没有Break时的警告 |
path | 在类路径、源文件路径中有不存在的路径时的警告 |
serial | 当在可序列化的类上缺少了serialVersionUUID时的警告 |
finally | 任何finally子句不能正常完成时的警告 |
all | 所有警告 |
抑制单类型的警告
@SuppressWarnings("unchecked")
public void addItems(String item){
@SuppressWarnings("rawtypes")
List items = new ArrayList();
items.add(item);
}
抑制多类型的警告
@SuppressWarnings(value={"unchecked", "rawtypes"})
public void addItems(String item){
List items = new ArrayList();
items.add(item);
}
抑制所有类型的警告
@SuppressWarnings("all")
public void addItems(String item){
List items = new ArrayList();
items.add(item);
}
3.2 元注解
元注解是java API提供的,是用于修饰注解的注解,通常用在注解的定义上:
元注解名称 | 功能描述 |
---|---|
@Retention | 标识这个注解是只在代码中,还是编入类文件中,或者是在运行时可以通过反射访问 |
@Documented | 标识这些注解是否包含在用户文档中 |
@Target | 标识这个注解的作用范围 |
@lnherited | 标识注解可被继承类获取 |
@Repeatable | 标识某注解可以在同一个声明上使用多次 |
3.2.1 @Retention
@Retention
用来定义该注解在哪一个级别可用,在源代码中(SOURCE)、类文件中(CLASS)或者运行时(RUNTIME)。
@Retention 源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
etentionPolicy 是一个枚举类型,它定义了被 @Retention 修饰的注解所支持的保留级别:
public enum RetentionPolicy {
//此注解类型的信息只会记录在源文件中,编译时将被编译器丢弃,也就是说
//不会保存在编译好的类信息中
SOURCE,
//编译器将注解记录在类文件中,但不会加载到JVM中。如果一个注解声明没指定范围,则系统
//默认值就是Class
CLASS,
//注解信息会保留在源文件、类文件中,在执行的时也加载到Java的JVM中,因此可以反射性的读取。
RUNTIME
}
3.2.2 @Documented
@Documented
:生成文档信息的时候保留注解,对类作辅助说明
3.2.3 @Target
@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Target源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
ElementType 是一个枚举类型,它定义了被 @Target 修饰的注解可以应用的范围:
public enum ElementType {
// 应用于类、接口(包括注解类型)、枚举 ElementType.TYPE
TYPE,
// 用于字段或者属性 ElementType.FIELE
FIELD,
// 用于方法 ElementType.MEHTOD
METHOD,
// 用于方法的参数
PARAMETER,
// 用构造方法
CONSTRUCTOR,
// 用于局部变量
LOCAL_VARIABLE,
// 用于包
PACKAGE,
// 1.8新增 用于类型变量
TYPE_PARAMETER,
// 1.8新增 用于任何使用类型的语句中
TYPE_USE,
}
3.2.4 @Inherited
@Inherited:说明子类可以继承父类中的该注解
表示自动继承注解类型。 如果注解类型声明中存在 @Inherited 元注解,则注解所修饰类的所有子类都将会继承此注解。
3.2.5 @Repeatable
@Repeatable 表示注解可以重复使用。
当我们需要重复使用某个注解时,希望利用相同的注解来表现所有的形式时,我们可以借助@Repeatable注解。
3.3 自定义注解
3.3.1 定义注解格式
public @interface 注解名{
}
如:定义一个名为Book的注解
public @interface Book {
字段类型 字段名1();
字段类型 字段名2();
}
3.3.2 字段类型的格式
属性的格式
- 格式1:数据类型 属性名();
- 格式2:数据类型 属性名() default 默认值;
public @interface Book {
String name(); // 书名
String author() ; // 作者
Double price() default 20.8; // 价格
}
tips:注解字段类型可以有如下:
- 八种基本数据类型(int,float,boolean,byte,double,char,long,short)
- String类型,Class类型,枚举类型,注解类型
- 以上所有类型的一维数组
3.3.3 自定义注解
定义一个注解:Book
- 包含属性:String value() 书名
- 包含属性:double price() 价格,默认值为 100
- 包含属性:String[] authors() 多位作者
示例代码:
// 可以出现在方法上 类上 字段上
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
public @interface Book {
String value();
double price() default 100.0;
String[] authors();
}
使用注解
public class BookShelf {
@Book(value = "《汉书》",price = 108,authors = {"班固","班昭"})
public void showBook(){
}
}
注意事项:
如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
如果属性没有默认值,那么在使用注解时一定要给属性赋值。
3.3.4 特殊属性value
当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给属性值,无论value是单值元素还是数组类型。
定义一个注解:
// 定义注解Book
public @interface Book {
// 书名
String value();
}
使用注解:
// 使用注解Book
public class BookShelf {
@Book("《史记》")
public void showBook(){
}
}
或者:
public class BookShelf {
@Book(value="《史记》")
public void showBook(){
}
}
如果注解中除了value属性还有其他属性,且至少有一个属性没有默认值,则在使用注解给属性赋值时,value属性名不能省略。
当注解中除了value还有其他属性时,在赋值时必须指定全部的属性名,value属性名不能省略。
第二十五章枚举
1.枚举概述
枚举(enum),全称enumeration
,是JDK 1.5 中引入的新特性。Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
在JDK1.5 之前,我们定义常量都是: public static fianl
。有了枚举之后,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
2.定义枚举类型
2.1 静态常量案例
我们使用静态常量来设置一个季节类:
public class Season {
public static final Integer SPRING = 1;
public static final Integer SUMMER = 2;
public static final Integer AUTUMN = 3;
public static final Integer WINTER = 4;
}
测试类
public class enumDemo01 {
public static void main(String[] args) {
switch (Season.SPRING) {
case 1:
System.out.println("Spring!"); // 具体的逻辑
break;
case 2:
System.out.println("Summer!"); // 具体的逻辑
break;
case 3:
System.out.println("Autumn!"); // 具体的逻辑
break;
case 4:
System.out.println("Winter!"); // 具体的逻辑
break;
}
}
}
2.2 枚举案例
Java 枚举类使用enum
关键字来定义,各个常量使用逗号来分割。
public enum Season {
SPRING,SUMMER,AUTUMN,WINTER
}
其中SPRING
、SUMMER
、AUTUMN
、WINTER
都是枚举项,它们都是本类的实例,本类一共就只有四个实例对象。并且只能通过这四个关键字获取Season类的示例对象,不能使用new来创建枚举类的对象
public class EnumTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
Season summer = Season.SUMMER;
Season autumn = Season.AUTUMN;
Season winter = Season.WINTER;
Season season = Season.SPRING;
System.out.println(season == spring);//true
}
}
2.3 枚举与switch
使用枚举,能让我们的代码可读性更强。
public class EnumTest02 {
public static void main(String[] args) {
Season season = Season.AUTUMN;
switch (season){
case SPRING:
System.out.println("春天~");
break;
case SUMMER:
System.out.println("夏天!");
break;
case AUTUMN:
System.out.println("秋天@");
break;
case WINTER:
System.out.println("冬天&");
break;
default:
System.out.println("错误的季节");
}
}
}
3. 枚举的用法
3.1 枚举类的成员
枚举类和正常的类一样,可以有实例变量,实例方法,静态方法等等
定义枚举类:
package enumTest.enumTest03;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 16:48
* @Description TODO
*/
public enum enumTest03 {
// 在枚举常量后面还有其他成员时,分号是必须的。枚举常量必须在枚举类中所有成员的上方声明
RED,BLUE,GREEN,YELLOW;
public String aaa="123";// 普通成员变量
public static String bbb="456";// 静态成员变量
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void method(){
System.out.println("enum hello~");
}
}
Tips:当枚举项后面有其他成员(构造方法、成员变量、成员方法)时,最后一个枚举项必须加分号;
测试类:
package enumTest.enumTest03;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 16:51
* @Description TODO
*/
public class enumTest {
public static void main(String[] args) {
// 访问静态变量
String bbb = enumDemo.bbb;
// 访问静态成员方法
enumDemo.method();
// 通过枚举项获取实例
enumDemo red = enumDemo.RED;
// 通过枚举实例调用成员方法
red.setName("红色");
// 通过枚举实例调用成员方法
System.out.println(red.getName()); // 红色
}
}
3.2 枚举类的构造方法
3.2.1 枚举的无参构造方法
枚举类也可以有构造方法,构造方法默认都是private修饰,而且只能是private。因为枚举类的实例不能让外界来创建!
默认情况下,所有的枚举项的创建都是调用枚举类的无参构造方法,
package enumTest.enumTest04;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 16:59
* @Description TODO
*/
public enum Direction {
// 在枚举常量后面还有其他成员时,分号是必须的。枚举常量必须在枚举类中所有成员的上方声明
FRONT,BEHIND,LEFT,RIGHT;
// 枚举类的构造方法都是private修饰的,可写可不写
Direction(){
System.out.println("Direction创建了...");
}
}
Tips:
- 1:当枚举项后面有其他成员(构造方法、成员变量、成员方法)时,最后一个枚举项必须加分号;
- 2:所有的枚举类的构造方法都是私有的(private关键字可加可不加)
测试类
package enumTest.enumTest04;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 16:59
* @Description TODO
*/
public class Test {
public static void main(String[] args) {
Direction direction=Direction.BEHIND;
}
}
Direction创建了...
Direction创建了...
Direction创建了...
Direction创建了...
Tips:一旦创建了枚举实例,便会初始化里面的所有枚举项;创建枚举项就等同于调用本类的无参构造器,所以FRONT、BEHIND、LEFT、RIGHT四个枚举项等同于调用了四次无参构造器
3.2.2 枚举的有参构造方法
枚举项就是枚举类的实例,在创建定义枚举项时其实就是创建枚举类的实例,因此在定义枚举项就要传递实际的参数
package enumTest.enumTest05;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 17:03
* @Description TODO
*/
public enum Week {
// 枚举项就是枚举类的实例,在创建定义枚举项时其实就是创建枚举的实例,因此在定义枚举项就要传递实际的参数
MONDAY("星期一",1),
TUESDAY("星期二"),
WEDNESDAY,
THURSDAY("星期四",3),
FRIDAY("星期五",4),
SATURDAY("星期六",5),
SUNDAY("星期六",4);
private String name;
private Integer loveLevel;
Week() {
}
Week(String name, Integer loveLevel) {
this.name = name;
this.loveLevel = loveLevel;
}
Week(String name) {
this.name = name;
}
}
测试类:
package enumTest.enumTest05;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 17:07
* @Description TODO
*/
public class Test {
public static void main(String[] args) {
Week friday = Week.FRIDAY;
friday.show();
System.out.println(friday);
System.out.println("---------------");
Week saturday = Week.SATURDAY;
saturday.show();
System.out.println(saturday);
System.out.println("---------------");
Week tuesday = Week.TUESDAY;
tuesday.show();
System.out.println(tuesday);
System.out.println("---------------");
Week wednesday = Week.WEDNESDAY;
wednesday.show();
System.out.println(wednesday);
System.out.println("---------------");
}
}
3.2.3 枚举中的抽象方法
枚举类中可以包含抽象方法,但是在定义枚举项时必须重写该枚举类中的所有抽象方法;
我们前面说过,每一个枚举项其实都是枚举类的实例对象,因此如果当前枚举类包含抽象方法时,在定义枚举项时就需要重写此枚举类的所有抽象方法,这跟我们以前使用的匿名内部类很相似;
首先定义一个抽象类(包含了抽象方法):
public abstract class AbstractSeason {
public abstract void fund();
}
实例化这个抽象类的时候,我们必须抽象其所有的抽象方法:
// 可以把abstractSeason看做是一个枚举项,在定义枚举项时必须重写枚举类的所有抽象方法
AbstractSeason abstractSeason = new AbstractSeason() {
@Override
public void fund() {
System.out.println("重写了这个抽象类的所有抽象方法");
}
};
当枚举类中含有抽象方法的时候,定义枚举项时,必须重写该枚举类中所有的抽象方法,
package enumTest.enumTest06;
/**
* @author 小宋学java
* @version 1.0
* @Data 2022/12/6 17:36
* @Description TODO
*/
public enum Season {
//SPRING; // 编译报错,定义枚举项时必须重写枚举类包含的所有抽象方法
SPRING(){
@Override
public void fun() {
System.out.println();
}
};
public abstract void fun();
}
4. Enum 类
4.1 Enum类中的方法
Java中,所有的枚举类都默认继承与java.lang.Enum
类,这说明Enum中的方法所有枚举类都拥有。另外Enum也继承与Object,因此所有的枚举类都拥有与Object类一样的方法;
Enum类中的方法如下:
Tips:枚举类除了不能拥有Object中的clone、finalize方法外,其他方法都能拥有;
Enum类新增(或重写Object)的方法:
-
int compareTo(E e)
:比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序(ordinal值) -
boolean equals(Object o)
:比较两个枚举常量是否相等; -
Class getDeclaringClass()
:返回此枚举类的Class对象,这与Object中的getClass()类似; -
int hashCode()
:返回枚举常量的hashCode
; -
String name()
:返回枚举常量的名字; -
int ordinal()
:返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0; -
String toString()
:把枚举常量转换成字符串 -
static T valueOf(Class enumType, String name)
:把字符串转换成枚举常量。
4.2 枚举的两个抽象方法
每个枚举类都有两个静态方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方;
static T[] values()
:返回本类所有枚举项;
4. Enum 类
4.1 Enum类中的方法
Java中,所有的枚举类都默认继承与java.lang.Enum
类,这说明Enum中的方法所有枚举类都拥有。另外Enum也继承与Object,因此所有的枚举类都拥有与Object类一样的方法;
Enum类中的方法如下:
[外链图片转存中…(img-6VmM7J42-1670480758453)]
Tips:枚举类除了不能拥有Object中的clone、finalize方法外,其他方法都能拥有;
Enum类新增(或重写Object)的方法:
-
int compareTo(E e)
:比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序(ordinal值) -
boolean equals(Object o)
:比较两个枚举常量是否相等; -
Class getDeclaringClass()
:返回此枚举类的Class对象,这与Object中的getClass()类似; -
int hashCode()
:返回枚举常量的hashCode
; -
String name()
:返回枚举常量的名字; -
int ordinal()
:返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0; -
String toString()
:把枚举常量转换成字符串 -
static T valueOf(Class enumType, String name)
:把字符串转换成枚举常量。
4.2 枚举的两个抽象方法
每个枚举类都有两个静态方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方;
static T[] values()
:返回本类所有枚举项;static T valueOf(String name)
:通过枚举项的名字返回枚举项