要求创建季节(Season) 对象,请设计并完成。
class Season{//类
private String name;
private String desc;//描述
//构造器
//getXX
//setXX
}
按照传统思路的代码如下:
public class Enumeration01 {
public static void main(String[] args) {
//使用
Season spring = new Season("春天","温暖");
Season winter = new Season("冬天","寒冷");
Season summer = new Season("夏天","炎热");
Season autumn = new Season("秋天","凉爽");
}
}
class Season{
private String name;
private String desc;
public Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
大家想一想这样写的话有什么不好的地方?
因为对于季节而言,它的对象是固定的四个值,不会更多。按照问题的引用这个思路,不能够体现季节是四个对象,因此,这样的设计不好
① 枚举对应英文(enumeration, 简写 enum)
② 枚举是一组常量的集合。
③ 可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。
① 自定义类实现枚举
② 使用 enum 关键字实现枚举
① 将构造器私有化,目的防止 直接 new
//1. 将构造器私有化,目的防止 直接 new
private Season01(String name, String desc) {
this.name = name;
this.desc = desc;
}
② 去掉 setXxx 方法, 防止属性被修改
//演示字定义枚举实现
class Season01{
private String name;
private String desc;
//1. 将构造器私有化,目的防止 直接 new
//2. 去掉 setXxx 方法, 防止属性被修改
private Season01(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
}
③ 在 Season 内部,直接创建固定的对象
//定义了四个固定的对象
public static final Season01 SPRING = new Season01("春天", "温暖");
public static final Season01 WINTER = new Season01("冬天", "寒冷");
public static final Season01 AUTUMN = new Season01("秋天", "凉爽");
public static final Season01 SUMMER = new Season01("夏天", "炎热");
总代码如下:
public class Enumeration {
public static void main(String[] args) {
System.out.println(Season01.AUTUMN);
System.out.println(Season01.SPRING);
}
}
//演示字定义枚举实现
class Season01{
private String name;
private String desc;
//定义了四个固定的对象
public static final Season01 SPRING = new Season01("春天", "温暖");
public static final Season01 WINTER = new Season01("冬天", "寒冷");
public static final Season01 AUTUMN = new Season01("秋天", "凉爽");
public static final Season01 SUMMER = new Season01("夏天", "炎热");
//1. 将构造器私有化,目的防止 直接 new
//2. 去掉 setXxx 方法, 防止属性被修改
//3. 在 Season 内部,直接创建固定的对象
private Season01(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season01{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
运行结果:
Season01{name='秋天', desc='凉爽'}
Season01{name='春天', desc='温暖'}
总结:
进行自定义类实现枚举,有如下特点:
①构造器私有化
②本类内部创建一组对象[四个 春夏秋冬]
③对外暴露对象(通过为对象添加 public final static 修饰符)
④可以提供 get 方法,但是不要提供 set
public class Enumeration03 {
public static void main(String[] args) {
System.out.println(Season2.AUTUMN);
System.out.println(Season2.SUMMER);
}
}
//演示使用 enum 关键字来实现枚举类
enum Season2 {//类
//如果使用了 enum 来实现枚举类
//1. 使用关键字 enum 替代 class
//2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
// SPRING("春天", "温暖") 解读 常量名(实参列表)
//3. 如果有多个常量(对象), 使用 ,号间隔即可
//4. 如果使用 enum 来实现枚举,要求将定义常量对象,写在前面
SPRING("春天", "温暖"),
WINTER("冬天", "寒冷"),
AUTUMN("秋天", "凉爽"),
SUMMER("夏天", "炎热")/*, What()*/;
private String name;
private String desc;//描述
private Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
① 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类。
这里说明一个小问题:
Hello.java文件是通过javac文件编译成Hello.class,Hello.class文件通过javap反编译为Hello.java文件。
② 传统的 public static final Season2 SPRING = new Season2("春天", "温暖");
简化成 SPRING("春天", "温暖"),
这里必须知道,它调用的是哪个构造器.
③ 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
//演示使用 enum 关键字来实现枚举类
enum Season2 {//类
What();//或者what;
private String name;
private String desc;//描述
private Season2() {//无参构造器
}
private Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
④ 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
SPRING("春天", "温暖"),
WINTER("冬天", "寒冷"),
AUTUMN("秋天", "凉爽"),
SUMMER("夏天", "炎热");
⑤ 枚举对象必须放在枚举类的行首。
enum Season2 {//类
//如果使用 enum 来实现枚举,要求将定义常量对象,写在前面
SPRING("春天", "温暖"),
WINTER("冬天", "寒冷"),
AUTUMN("秋天", "凉爽"),
SUMMER("夏天", "炎热")/*, What()*/;
private String name;
...
}
T1下面代码是否正确, 并说明表示的含义?
enum Gender{ //1min
BOY , GIRL; //这里其实就是调用 Gender 类的无参构造器
}
- 上面语法是 ok
- 有一个枚举类 Gender, 没有属性。
- 有两个枚举对象 BOY, GIRL, 使用的无参构造器创建.
说明:使用关键字 enum 时,会隐式继承 Enum 类, 这样我们就可以使用 Enum [看下源码定义.]
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
}
① toString:Enum 类已经重写过了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息
② name:返回当前对象名(常量名),子类中不能重写
//使用 Season2 枚举类,来演示各种方法
Season2 autumn = Season2.AUTUMN;
//输出枚举对象的名字
System.out.println(autumn.name());
③ ordinal:返回当前对象的位置号,默认从 0 开始
//ordinal() 输出的是该枚举对象的次序/编号,从 0 开始编号
//AUTUMN 枚举对象是第一个,因此输出 0
System.out.println(autumn.ordinal());
④ values:返回当前枚举类中所有的常量
//从反编译可以看出 values 方法,返回 Season2[]
//含有定义的所有枚举对象
Season2[] values = Season2.values();
System.out.println("===遍历取出枚举对象(增强 for)====");
for (Season2 season: values) {//增强 for 循环
System.out.println(season);
}
⑤ valueOf:将字符串转换成枚举对象,要求字符串必须
为已有的常量名,否则报异常!
//valueOf:将字符串转换成枚举对象,要求字符串必须
为已有的常量名,否则报异常
//执行流程
//1. 根据你输入的 "AUTUMN" 到 Season2 的枚举对象去查找
//2. 如果找到了,就返回,如果没有找到,就报错
Season2 autumn1 = Season2.valueOf("AUTUMN");
System.out.println("autumn1=" + autumn1);//autumn1=Season{name='秋天', desc='凉爽'}
System.out.println(autumn == autumn1)//true
⑥ compareTo:比较两个枚举常量,比较的就是编号!
System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));
看编号:
SPRING("春天", "温暖"),//0
WINTER("冬天", "寒冷"),//1
AUTUMN("秋天", "凉爽"),//2
SUMMER("夏天", "炎热");//3
Season2.AUTUMN 的编号[2] - Season2.SUMMER 的编号[3]
声明 Week 枚举类,其中包含星期一至星期日的定义; MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
使用 values 返回所有的枚举数组, 并遍历 , 输出如下:
===所有星期的信息如下===
星期一
星期二
星期三
星期四
星期五
星期六
星期日
代码:
public class EnumExercise02 {
public static void main(String[] args) {
Week[] weeks=Week.values();
System.out.println("===所有星期的信息如下===");
for(Week week:weeks){
System.out.println(week);
}
}
}
enum Week{
//定义 Week 的枚举对象
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");
private String name;
private Week(String name) {//构造器
this.name = name;
}
@Override
public String toString() {
return name;
}
}
① 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制。
② 枚举类和普通类一样,可以实现接口,如下形式。
enum 类名 implements 接口 1,接口 2{}
示例代码:
public class EnumDetail {
public static void main(String[] args) {
Music.CLASSICMUSIC.playing();
}
}
class A {
}
//1.使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制
//enum Season3 extends A {
//
//}
//2.enum 实现的枚举类,仍然是一个类,所以还是可以实现接口的.
interface IPlaying {
public void playing();
}
enum Music implements IPlaying {
CLASSICMUSIC;
@Override
public void playing() {
System.out.println("播放好听的音乐...");
}
}
①注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
②和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
③在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素
三个基本的 Annotation
- @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
- @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
- @SuppressWarnings: 抑制编译器警告
override:限定某个方法,是重写父类方法,该注解只能用于方法
//override:限定某个方法,是重写父类方法,该注解只能用于方法
class Father {
public void fly() {
System.out.println("Father fly.….");
}
}
class Son extends Father {
@Override //说明
public void fly() {
System.out.println("Son fly..");
}
}
解读:
@Override
注解放在fly 方法
上,表示子类的fly 方法
时重写了父类的fly
- 这里如果没有写
@Override
还是重写了父类fly
- 如果你写了
@Override
注解,编译器就会去检查该方法是否真的重写了父类的方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误.- 看看
@Override
的定义(源码)
解读: 如果发现@interface
表示一个 注解类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
补充说明:@interface的说明
@interface
不是interface
,是注解类是jdk5.0之后加入的
Override使用说明
- @Override表示指定重写父类的方法((从编译层面验证),如果父类没有fly方法,则会报错
- 如果不写@Override注解,而父类仍有public void fly(){},仍然构成重写
- @Override只能修饰方法,不能修饰其它类,包,属性等等
- 查看@Override注解源码为@Target(ElementType.METHOD),说明只能修饰方法
- @Target是修饰注解的注解,称为元注解,记住这个概念.
@Deprecated
: 用于表示某个程序元素(类, 方法等)已过时。
public class Deprecated_ {
public static void main(String[] args) {
A a = new A();
a.hi();
System.out.println(a.n1);
}
}
@Deprecated
class A {
@Deprecated
public int n1 = 10;
@Deprecated
public void hi(){
}
}
解读:
- @Deprecated 修饰某个元素, 表示该元素已经过时
- 即不再推荐使用,但是仍然可以使用
- 查看 @Deprecated 注解类的源码
- 可以修饰方法,类,字段, 包, 参数 等等
- @Deprecated 可以做版本升级过渡使用
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@SuppressWarnings
: 抑制编译器警告
all,抑制所有警告
想了解更多?请参考视频:韩顺平Java
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("all")
public class SuppressWarnings_ {
public static void main(String[] args) {
List list = new ArrayList();
list.add("jack");
list.add("tom");
list.add("mary");
int i;
System.out.println(list.get(1));
}
public void f1() {
List list = new ArrayList();
list.add("jack");
list.add("tom");
list.add("mary");
int i;
System.out.println(list.get(1));
}
}