知识点1:枚举类
定义和格式
JDK1.5之前需要自定义枚举类
JDK 1.5 新增的 enum 关键字用于定义枚举类
若枚举只有一个成员, 则可以作为一种单例模式的实现方式
当一个类的对象是可数的情况下,就可以使用枚举.
枚举类的理解:类的对象只有有限个,确定的。则此类可以看做是枚举类。
如何自定义枚举类
//自定义枚举类
class Season {
//1. 声明每个对象拥有的属性:private final修饰
private final String SEASON_NAME;
private final String SEASON_DESC;
//2. 私有化类的构造器
private Season(String seasonName, String seasonDesc) {
this.SEASON_NAME = seasonName;
this.SEASON_DESC = seasonDesc;
}
//3. 创建枚举类中的对象:public static final
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("冬天", "白雪皑皑");
//4. 提供toString()
@Override
public String toString() {
return "Season [SEASON_NAME=" + SEASON_NAME + ", SEASON_DESC=" + SEASON_DESC + "]";
}
public String getSEASON_NAME() {
return SEASON_NAME;
}
public String getSEASON_DESC() {
return SEASON_DESC;
}
}
使用enum关键字定义枚举类
//使用enum关键字定义枚举类
enum Season1 implements Info {
//1. 创建枚举类中的对象,声明在enum枚举类的首位
SPRING("春天", "春暖花开"),
SUMMER("夏天", "夏日炎炎"),
AUTUMN("秋天", "秋高气爽"),
WINTER("冬天", "白雪皑皑");
//2. 声明每个对象拥有的属性:private final修饰
private final String SEASON_NAME;
private final String SEASON_DESC;
//3. 私有化类的构造器
private Season1(String seasonName, String seasonDesc) {
this.SEASON_NAME = seasonName;
this.SEASON_DESC = seasonDesc;
}
public String
getSEASON_NAME() {
return SEASON_NAME;
}
public String
getSEASON_DESC() {
return SEASON_DESC;
}
@Override
public void show() {
System.out.println("这是一个美好的季节!");
}
}
枚举类实现接口中的方法
interface Info {
void show();
}
//使用enum关键字定义枚举类
enum Season1 implements Info {
//1. 创建枚举类中的对象,声明在enum枚举类的首位
SPRING("春天", "春暖花开") {
public void show() {
System.out.println("春天在哪里?");
}
},
SUMMER("夏天", "夏日炎炎") {
public void show() {
System.out.println("宁静的夏天");
}
},
AUTUMN("秋天", "秋高气爽") {
public void show() {
System.out.println("秋天是用来分手的季节");
}
},
WINTER("冬天", "白雪皑皑") {
public void show() {
System.out.println("2002年的第一场雪");
}
};
//2. 声明每个对象拥有的属性:private final修饰
private final String SEASON_NAME;
private final String SEASON_DESC;
//3. 私有化类的构造器
private Season1(String seasonName, String seasonDesc) {
this.SEASON_NAME = seasonName;
this.SEASON_DESC = seasonDesc;
}
public String getSEASON_NAME() {
return SEASON_NAME;
}
public String getSEASON_DESC() {
return SEASON_DESC;
}
}
枚举类的主要方法
枚举类的主要方法:
values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。
valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常。
枚举类的属性
枚举类对象可以有属性
若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的传入参数
特点:
必须在枚举类的第一行声明枚举类对象。
枚举类和普通类的区别:
1、使用 enum 定义的枚举类默认继承了 java.lang.Enum 类
2、枚举类的构造器只能使用 private 访问控制符
3、枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾). 列出的实例系统会自动添加 public static final 修饰。
JDK 1.5 中可以在 switch 表达式中使用Enum定义的枚举类的对象作为表达式, case 子句可以直接使用枚举值的名字, 无需添加枚举类作为限定
/**
* 枚举 : 对象可数的类型, 不能再创建新对象.
*/
enum Season { // public static final 修饰的量. 称为全局常量
// 给Week枚举加上属性, String feel. 添加构造器. 改造toString().
SPRING("绿色"), SUMMER("红色"), AUTUMN, WINTER;
{
color = "白色"; // 非静态语句块和显式赋值的顺序是按照写的顺序来执行的 并且它们都是先于构造器
}
private String color = "黑色";
private Season() {}
private Season(String color) { // 构造器必须是私有的
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return super.toString() + " Season{" +
"color='" + color + '\'' +
'}';
}
}
注解Annotation
主要内容
1、JDK内置的基本注解类型(3个)
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告
2、自定义注解类型
3、对注解进行注解(4个)
4、利用反射获取注解信息(在反射部分涉及)
注解 (Annotation) 概述
从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是 Annotation(注解)
Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理. 通过使用 Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息.
Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在 Annotation 的 “name=value” 对中.
Annotation 能被用来为程序元素(类, 方法, 成员变量等) 设置元数据
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素
三个基本的 Annotation:
@Override: 限定重写父类方法, 该注释只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告
自定义Annotation
如何自定义注解(了解)
参照@SuppressWarnings定义
① 使用@interface来声明
② 内部可以声明属性,属性类型限于:八种基本数据类型、String类型、Class类型、enum类型、Annotation
类型、以上所有类型的数组
③ 如果注解内部不定义任何属性,则称为标识注解
④ 属性可以声明默认值,使用default定义
说明:要想自定义的注解在使用在相关结构的位置上起作用,必须结合后面的反射。通过反射获取相应的注解及注解上的属性的值,进行必要的操作。
public @interface MyAnnotation{
String name() default “atguigu";
}
没有成员定义的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数据 Annotation
提取 Annotation 信息
1、JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 接口, 该接口代表程序中可以接受注解的程序元素
2、当一个 Annotation 类型被定义为运行时 Annotation 后, 该注释才是运行时可见, 当 class 文件被载入时保存在 class 文件中的 Annotation 才会被虚拟机读取
3、程序可以调用 AnnotationElement 对象的如下方法来访问 Annotation 信息
JDK 的元 Annotation
JDK 的元 Annotation 用于修饰其他 Annotation 定义
JDK5.0提供了专门在注解上的注解类型,分别是:
1、Retention 用于指定该 Annotation 的生命周期
SOURCE:编译不保留 ; CLASS(默认行为):编译保留,运行不保留;RUNTIME:编译保留,运行也保留
2、Target 用于指定被修饰的 Annotation 能用于修饰哪些程序元素。
3、Documented 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档
4、Inherited 被它修饰的 Annotation 将具有继承性。
说明:一般注解都会提供两个元注解: @Retention,@Target。
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值:
RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释
RetentionPolicy.CLASS: 编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认值
RetentionPolicy.RUNTIME:编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注释. 程序可以通过反射获取该注释
public enum RetentionPolicy{
SOURCE,
CLASS,
RUNTIME
}
@Retention(RetentionPolicy.SOURCE)
@interface MyAnnotation1{ }
@interface MyAnnotation2{ }
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{ }
常用元注解Annotation
@Target: 用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素. @Target 也包含一个名为 value 的成员变量.
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
定义为Documented的注解必须设置Retention值为RUNTIME。
@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
实际应用中,使用较少
package com.atguigu.javase.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解 : 是一种特殊的注释, 特殊在于可以被编译器, VM识别. 本质上是一个修饰符, 注解都不能修饰语句.
* @Override 作用是提醒编译器, 它修饰的方法是一个覆盖方法, 请帮助我们作检查 , 方法覆盖条件的检查.
* 只可以修饰方法.
*
* @Deprecated 作用是提醒编译器,提醒使用者 它修饰的目标不推荐使用
* 它可以
* 修饰类(TYPE), 属性(FIELD), 构造器(CONSTRUCTOR), 方法(METHOD),
* 局部变量(LOCAL_VARIABLE), 参数(PARAMETER)
*
* @SuppressWarnings 抑制编译器警告, 在使用时必须传参, 说明它内部有属性.
*
* 元注解 : 注解的注解, 约束注解的使用的注解.
* @Target 作用是约束注解可以修饰的目标.可以用在什么位置, 默认情况是它可以修饰任意目标
* ElementType.TYPE 类型(类类型,接口类型)
* ElementType.FIELD 属性
* ElementType.METHOD 方法
* ElementType.CONSTRUCTOR 构造器
* ElementType.PARAMETER 参数
*
* @Retention 作用是约束注解可以停留在什么时期, 是只在源文件中呢, 还是在类文件中, 还是都在且运行时能获取.
*/
// 自定义注解, 可以修饰任意目标. 这是一个标记型注解
//@interface MyAnnotation {}
// 自定义注解, 可以修饰任意目标. 这是一个有参数的注解, 默认可以修饰任意目标
/*
@interface MyAnnotation {
int id() default 200; // 属性可以有缺省值.
String name() default "缺省值";
}*/
/*
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER}) // 自定义注解只可以修饰类和属性. 其他都不行了.默认情况下此注解停留在类文件中
@interface MyAnnotation {
int id() default 200;
String name() default "缺省值";
}
*/
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER}) // 自定义注解只可以修饰类和属性. 其他都不行了.
@Retention(RetentionPolicy.RUNTIME) // MyAnnotation注解就可以在运行时通过反射获取并处理了..
@interface MyAnnotation {
int id() default 200;
String name() default "缺省值";
}
//@Override
@Deprecated
@MyAnnotation(id = 1, name="abc")
class Person {
//@Override
private String name;
@Deprecated
@MyAnnotation(name="yyy", id = 2) private int age;
private String gender;
@Deprecated
/*@MyAnnotation(name="zzz")*/ public Person() {
}
//@Override
// <init>()
public Person(@Deprecated String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Deprecated
@SuppressWarnings({"unused", "null"})
/*@MyAnnotation(name="zzz")*/ public String getName() {
@Deprecated int n;
double d;
//System.out.println(n);
/*@MyAnnotation*/ int[] arr = null;
System.out.println(arr.length);
return name;
}
/*@MyAnnotation*/ public void setName(@MyAnnotation String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override /*@MyAnnotation*/ public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
public class AnnotationTest {
public static void main(String[] args) {
new Person("张三", 30, "男");
}
}