Java基础之(二十四)枚举类
来源:互联网 发布:流程优化的意义 编辑:程序博客网 时间:2024/06/06 14:01
:说明
在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有四个对象(春夏秋冬);再比如行星类,目前只有九个对象。这种实例有限而且固定的类就被称之为枚举类。
手动实现枚举类
如果需要手动实现枚举类,可以采用如下设计方式:
通过private将构造器隐藏起来
把这个类的所有可能实例都用public static final 修饰的类变量来保存
如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配的实例。
下面程序将定义一个Season类,这个类只能产生四个对象,该Season类被定义成一个枚举类:
public class Season{ //把Season类定义成不可变的,将其属性也定义成final private final String name; private final String desc; public static final Season SPRING = new Season("春天" , "趁春踏青"); public static final Season SUMMER = new Season("夏天" , "夏日炎炎"); public static final Season FALL = new Season("秋天" , "秋高气爽"); public static final Season WINTER = new Season("冬天" , "围炉赏雪"); public static Season getSeaon(int seasonNum) { switch(seasonNum) { case 1 : return SPRING; case 2 : return SUMMER; case 3 : return FALL; case 4 : return WINTER; default : return null; } } //将构造器定义成private访问权限 private Season(String name , String desc) { this.name = name; this.desc = desc; } //只为name和desc属性提供getter方法 public String getName() { return this.name; } public String getDesc() { return this.desc; }}
上面的Season类就是一个不可变类,在上面的程序中包含了4个static final常量Field,这四个常量Field就代表了该类所能创建的对象。当其他程序需要使用Season对象时,既可通过如Season.SPRIN的方式来取得对象,也可通过getSeason静态方法来获得Season对象。
下面程序示范了如何使用Season类:
public class TestSeason{ public TestSeason(Season s) { System.out.println(s.getName() + ",这真是一个"+ s.getDesc() + "的季节"); } public static void main(String[] args) { //直接使用Season的FALL常量代表一个Season对象 new TestSeason(Season.FALL); }}
从上面程序中不难看出,使用枚举类可以使程序更加健壮,避免创建对象的任意性。
枚举类入门
Java中用enum关键字定义枚举类。枚举类是一种特殊的类,它可以有自己的Field、方法,可以实现一个或多个接口,也可以定义自己的构造器。一个Java源文件里只能定义一个Public访问权限的枚举类,且该源文件也必须和该枚举类类名相同。
枚举类与普通类的区别:
枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是继承Object类。其中java.long.Enum类实现了java.lang.Serializable和java.lang.Comparable接口。
使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。
枚举类的构造器只能用private访问控制符修饰,如果省略了控制符,则默认为private。
枚举类的所有实例必须在枚举类的第一行显式列出。列出这些实例时,系统会自动添加public static final修饰。
所有的枚举类都提供了一个values方法,该方法可以很方便地遍历所有的枚举值。
下面程序定义了一个SeasonEnum枚举类。
public enum SeasonEnum{ //在第一行列出四个枚举实例 SPRING,SUMMER,FALL,WINTER;}
如果需要使用该枚举类的某个实例,则可使用EnumClass.variable的形式,如SeasonEnum.SPRING。
public class TestEnum{ public void judge(SeasonEnum s) { //switch语句里的表达式可以是枚举值 switch (s) { case SPRING: System.out.println("春暖花开,正好踏青"); break; case SUMMER: System.out.println("夏日炎炎,适合游泳"); break; case FALL: System.out.println("秋高气爽,进补及时"); break; case WINTER: System.out.println("冬日雪飘,围炉赏雪"); break; } } public static void main(String[] args) { //所有枚举类都有一个values方法,返回该枚举类的所有实例 for (SeasonEnum s : SeasonEnum.values()) { System.out.println(s); } new TestEnum().judge(SeasonEnum.SPRING); }}
输出结果:SPRINGSUMMERFALLWINTER春暖花开,正好踏青
上main程序测试了枚举类的用法,该类通过value方法返回了SeasonEnum枚举类的所有实例,并通过循环迭代输出SeasonEnum枚举类的所有实例。
不仅如此,上面程序的switch表达式中还使用了Seasonenum对象作为表达式,switch的控制表达式可以是任何枚举类型,后面case表达式中的值直接使用枚举值的名字,无需添加枚举类作为限定。
枚举类的Field、方法和构造器
枚举类也是一种类,只是它是一种比较特殊的类,因此它一样可以定义Field、方法。下面程序将定义一个Gender枚举类:
public enum Gender{ MALE,FEMALE; //定义一个public修饰的实例变量 public String name;}
上面的枚举类里定义了一个名为name的实例变量,并且将他定义成一个public访问权限的。下面通过如下程序来使用枚举类:
public class TestGender{ public static void main(String[] args) { //通过Enum的value方法来获取指定枚举类的枚举值 Gender g = Enum.valueOf(Gender.class , "FEMALE"); //直接为枚举类的Field赋值 g.name = "女"; //直接访问枚举类的Field值 System.out.println(g + "代表:" + g.name); }}
上面程序使用枚举类时与使用一个普通类时没有太大的区别,只是产生Gender对象时的方式不同,枚举类的实例只能是枚举值,而不是随意的通过new关键字来创建枚举类对象。
程序中我们恰好设置了g.name = “女”,要是采用g.name = “男”,那就会出现FEMALE代表男的情况,为此我们改进Gender类的设计:
public enum Gender { MALE,FEMALE; private String name; public void setName(String name) { switch (this) { case MALE: if (name.equals("男")) { this.name = name; } else { System.out.println("参数错误"); return; } break; case FEMALE: if (name.equals("女")) { this.name = name; } else { System.out.println("参数错误"); return; } break; } } public String getName() { return this.name; }}
上面程序把name设置成private,从而避免其它程序直接访问该name实例变量,必须通过setName()方法来修改Gender实例中的变量。看如下测试程序:
public class TestGender{ public static void main(String[] args) { Gender g = Enum.valueOf(Gender.class , "FEMALE"); g.setName("女"); System.out.println(g + "代表:" + g.getName()); //此时提供name值时将会提示参数错误 g.setName("男"); System.out.println(g + "代表:" + g.getName()); }}
枚举类通常被设计成不可变类,也就是说它的Field值不应该允许改变,这样会更安全,因此我们将枚举类的Field都用private final修饰。
因为我们将所有的Field都使用了private final修饰,所以必须在构造器里为这些Field指定初始值。因此应该为枚举类显示定义带参数的构造器。
一旦为枚举类显示定义了带参数的构造器,列出枚举值时就必须对应地传入参数。
public enum Gender { //此处的枚举值必须调用对应构造器来创建 MALE("男"),FEMALE("女"); private String name; //枚举类的构造器只能使用private修饰 private Gender(String name) { this.name = name; } public String getName() { return this.name; }}
从上面程序中可以看出,当为Gender枚举类创建了一个Gender(String name)构造器之后,列出枚举值就应该传入对应参数。也就是说,在枚举类中定义枚举值时,实际上就是调用构造器创建枚举类对象,只是这里无需使用new关键字,也无须显式调用构造器。前面列出枚举值时无须传入参数,仅仅是因为前面的枚举类包含无参数的构造器。
上面程序中的MALE("男"),FEMALE("女");
实际上等同于如下两行代码:
public static final Gender MALE = new Gender("男");public static final Gender FEMALE = new Gender("女");
实现接口的枚举类
枚举类也可以实现一个或多个接口,当然也需要实现该接口包含的方法。下面程序定义了一个GenderDesc接口:
public interface GenderDesc{ void info();}
上面GenderDesc接口定义了一个info方法,下面的Gender枚举类实现了该接口,并实现了该接口里包含的info方法:
public enum Gender implement GenderDesc{ //此处的枚举值必须调用对应构造器来创建 MALE("男"),FEMALE("女"); private String name; //枚举类的构造器只能使用private修饰 private Gender(String name) { this.name = name; } public String getName() { return this.name; } public void info(){ System.out.println("这是一个用于定义性别Field的枚举类"); }}
枚举类用implement实现接口,实现接口里包含的抽象方法,这似乎与普通类一样。
如果由枚举类来实现接口里的方法,则每个枚举类在调用该方法时都有相同的行为方式。如果需要每个枚举类在调用该方法时有不同的行为方式,则可以让每个枚举值分别实现该方法,每个枚举值提供不同的实现方式。在下面的程序中不同的枚举值对info方法的实现各不相同:
public enum Gender implements GenderDesc{ //此处的枚举值必须调用对应构造器来创建 MALE("男") { public void info() { System.out.println("这个枚举值代表男性"); } }, FEMALE("女") { public void info() { System.out.println("这个枚举值代表女性"); } }; private String name; //枚举类的构造器只能使用private修饰 private Gender(String name) { this.name = name; } public String getName() { return this.name; }}
上面代码如下部分
MALE("男") { public void info() { System.out.println("这个枚举值代表男性"); } }, FEMALE("女") { public void info() { System.out.println("这个枚举值代表女性"); } };
看起来有些奇怪,当我们创建MALE和FEMALE两个枚举值时,后面又紧跟了一对花括号,这对花括号里包含了一个info方法定义。跟前面的匿名内部类联系起来,花括号部分实际上就是类体部分,在这种情况下,当创建MALE、FEMALE枚举值时,并不是直接创建Gender枚举类的实例,而是相当于创建Gender的匿名子类的实例。
包含抽象方法的枚举类
假设有一个Operation枚举类,它的四个枚举值PLUS,MINUS,TIMES,DEVIDE分别代表加减乘除四种运算:
public enum Operation{ PLUS, MINUS, TIMES, DIVIDE; //为枚举类定义一个方法,用于实现不同的运算 public double eval(double x, double y) { switch(this) { case PLUS: return x + y; case MINUS: return x - y; case TIMES: return x * y; case DIVIDE: return x / y; default: return 0; ———————— a } } public static void main(String[] args) { System.out.println(Operation2.PLUS.eval(3, 4)); System.out.println(Operation2.MINUS.eval(5, 4)); System.out.println(Operation2.TIMES.eval(5, 4)); System.out.println(Operation2.DIVIDE.eval(5, 4)); }}
a处这行代码完全没有存在的必要,因为this代表了枚举类的一个值,这个值只可能是PLUS,MINUS,TIMES,DEVIDE4个值,根本没有其他的值,但是不写有编译不通过。
实际上PLUS,MINUS,TIMES,DEVIDE4个值对eval方法各有不同的实现,因此我们可以采用前面介绍的方法,让它们分别为四个枚举值提供eval的实现,然后在Operation枚举类中定义一个eval的抽象方法。
public enum Operation2{ PLUS { public double eval(double x , double y) { return x + y; } }, MINUS { public double eval(double x , double y) { return x - y; } }, TIMES { public double eval(double x , double y) { return x * y; } }, DIVIDE { public double eval(double x , double y) { return x / y; } }; //为枚举类定义一个抽象方法,这个抽象方法由不同枚举值提供不同的实现 public abstract double eval(double x, double y); public static void main(String[] args) { System.out.println(Operation.PLUS.eval(3, 4)); System.out.println(Operation.MINUS.eval(5, 4)); System.out.println(Operation.TIMES.eval(5, 4)); System.out.println(Operation.DIVIDE.eval(5, 4)); }}
枚举类里定义抽象方法时不能使用abstract关键字将枚举类定义成抽象类,因为系统会自动为其添加abstract关键字,但因为枚举类需要显式创建枚举值,而不是作为父类,因此定义每个枚举值时必须为抽象方法提供实现。
关于枚举类的七种用法这里还有一些介绍哦:
http://blog.jobbole.com/31597/
- Java基础之(二十四)枚举类
- Java基础---Java循环之for(二十四)
- java基础整理二十四(网络编程二)
- Java程序员从笨鸟到菜鸟之(二十四)Xml基础详解和DTD验证
- Java程序员从笨鸟到菜鸟之(二十四)Xml基础详解和DTD验证
- Java程序员从笨鸟到菜鸟之(二十四)Xml基础详解和DTD验证
- Java程序员从笨鸟到菜鸟之(二十四)Xml基础详解和DTD验证
- java 从零开始,学习笔记之基础入门<JDBC>(二十四)
- java基础之 枚举
- Java基础之枚举
- java基础之枚举
- JAVA基础之枚举
- java基础之枚举
- java 基础之枚举
- java基础之枚举
- java基础之枚举
- java基础之枚举
- Java 基础之-枚举
- 多线程(三)线程控制之线程让步
- scala基础语法
- 常见排序算法小结
- 线段树,树状数组,RMQ之间的区别与联系
- Android HTTP网络通信
- Java基础之(二十四)枚举类
- 从OC到swift的一些总结
- 20个很有用的CSS技巧
- Eclipse+Maven创建webapp项目<二>
- Android进阶之NDK开发入门
- Android代码书写规范
- 初学C语言:剩下的树
- 宏函数和自定义函数
- 编程中的经典语录