java中的枚举类_Java 枚举类

手动实现枚举类

手动实现枚举类

实例有限而且固定的类,在Java里被称为枚举类。

早期采用通过定义类的方式来实现,可以采用如下设计方式

通过private将构造器隐藏起来

把这个类的所有可能实例都使用public static final 修饰的类变量来保存

如果与必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配的实例

使用枚举类可以使程序更加健壮,避免创建对象的随意性

Java从JDK1.5后就增加了对枚举类的支持。

枚举类入门

Java5新增了一个enum关键字(它与class、interface关键字的地位相同),用以定义枚举类。枚举类是一种特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或多个接口,也可以定义自己的构造器。一个Java源文件中最多只能定义一个public访问权限的枚举类,且该Java源文件也必须和该枚举类的类名相同。

枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显示继承其他父类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口。

使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。

枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,则默认使用private修饰;如果强制指定访问控制符,则只能指定private修饰符。

枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例。列出这些实例时,系统会自动添加public static final 修饰,无须程序员显式添加。

枚举类默认提供了一个values()方法,该方法可以很方便地遍历所有的枚举值。

public enum SeasonEnum

{

//在第一行列出4个枚举实例

SPRING,SUMMER,FALL,WINTER;

}

编译上面Java程序,将生成一个SeasonEnum.class文件,这表明枚举类是一个特殊的Java类。

所有的枚举值之间以英文逗号(,)隔开,枚举值列举结束后以英文分号作为结束。这些枚举值代表了该枚举类的所有可能的实例。

public class EnumTest

{

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);

}

//使用枚举实例时,可通过EnumClass.variable形式来访问

new EnumTest().judge(SeasonEnum.SPRING);

}

}

当switch控制表达式使用枚举类型时,后面case表达式中的值直接使用枚举值的名字,无须添加枚举类作为限定。

java.lang.Enum类中提供了如下几个方法:

int compareTo(E o):该方法用于与指定枚举对象比较顺序,同一个枚举实例只能与相同类型的枚举实例进行比较。如果该枚举对象位于指定枚举对象之后,则返回正整数;如果该枚举对象位于指定枚举对象之前,则返回负整数,否则返回零。

String name():返回此枚举实例的名称,这个名称就是定义枚举类时列出的所有枚举值之一。与此方法相比,大多数程序员应该优先考虑使用toString()方法,因为toString()方法返回更加用户友好的名称。

int ordinal():返回枚举值在枚举类中的索引值(就是枚举值在枚举声明中的位置,第一个枚举值的索引值为零)。

String toString():返回枚举常量的名称,与name方法相似,但toString()方法更常用。

public static > T valueOf(ClassenumType, String name):这是一个静态方法,用于返回指定枚举类中指定名称的枚举值。名称必须与在该枚举类中声明枚举值时所用的标识符完全匹配,不允许使用额外的空白字符。

当程序使用System.out.println(s)语句来打印枚举值时,实际上输出的是该枚举值的toString()方法,也就是输出该枚举值的名字。

枚举类的成员变量、方法和构造器

枚举类的实例只能是枚举值,而不是随意地通过new来创建枚举类对象。

public enum Gender

{

MALE,FEMALE;

//定义一个public修饰的实例变量

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();

}

}

public class GenderTest

{

public static void main(String[] args)

{

//通过Enum的valueOf()方法来获取指定枚举类的枚举值

//Gender gender = Enum.valueOf(Gender.class, "FEMALE");

Gender g = Gender.valueOf("FEMALE");

g.setName("女");

System.out.println(g+"代表:"+g.getName());

g.setName("男");

System.out.println(g+"代表:"+g.getName());

}

}

枚举类通常应该设计成不可变类,成员变量值不允许改变,将枚举类的成员变量都使用private final修饰。如果将所有的成员变量都使用final修饰符来修饰,必须在构造器里为这些成员变量指定初始值,为枚举类显式定义带参数的构造器。

一旦为枚举类显式定义了带参数的构造器,列出枚举值时就必须对应地传入参数。

public enum Gender

{

//此处的枚举值必须调用对应的构造器来创建

MALE("男"),FEMAL("女");

private final String name;

private Gender(String name)

{

this.name =name;

}

public String getName()

{

return this.name();

}

}

实现接口的枚举类

枚举类也可以实现一个或多个接口。与普通类实现一个或多个接口完全一样,枚举类实现一个或多个接口时,也需要实现该接口所包含的方法。

public interface GenderDesc

{

void info();

}

如果由枚举类来实现接口里的方法,则每个枚举值在调用该方法时都有相同的行为方式(因为方法体完全一样)。如果需要每个枚举值在调用该方法时呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法,每个枚举值提供不同的实现方式,从而让不同的枚举值调用该方法时具有不同的行为方式。

public enum Gender implements GenderDesc

{

// 此处的枚举值必须调用对应构造器来创建

MALE("男")

// 花括号部分实际上是一个类体部分

{

public void info()

{

System.out.println("这个枚举值代表男性");

}

},

FEMALE("女")

{

public void info()

{

System.out.println("这个枚举值代表女性");

}

};

// 其他部分与codes\06\6.9\best\Gender.java中的Gender类完全相同

private final String name;

// 枚举类的构造器只能使用private修饰

private Gender(String name)

{

this.name = name;

}

public String getName()

{

return this.name;

}

// 增加下面的info()方法,实现GenderDesc接口必须实现的方法

public void info()

{

System.out.println(

"这是一个用于用于定义性别的枚举类");

}

}

当创建MALE和FEMALE两个枚举值时,后面又紧跟了一对花括号,这对花括号里包含了一个info()方法定义。花括号部分实际上就是一个类体部分,在这种情况下,当创建MALE和FEMALE枚举值时,并不是直接创建Gender枚举类的实例,而是相当于创建Gender的匿名子类的实例。

并不是所有的枚举类都使用了final修饰。非抽象的枚举类才默认使用final修饰。对于一个抽象的枚举类而言——只要它包含了抽象方法,它就是抽象枚举类,系统会默认使用abstract修饰,而不是使用final修饰。

编译上面的程序,生成了Gender.class、Gender$1.class和Gender$2.class三个文件,证明了:MALE和FEMALE实际上是Gender匿名子类的实例,而不是Gender类的实例。当调用MALE和FEMALE两个枚举值的方法时,就会看到两个枚举值的方法表现不同的行为方式。

包含抽象方法的枚举类

public enum Operation

{

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(8, 8));

System.out.println(Operation.DIVIDE.eval(1, 5));

}

}

枚举类里定义抽象方法时不能使用abstract关键字将枚举类定义成抽象类(因为系统自动会为它添加abstract关键字),但因为枚举类需要显式创建枚举值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现,否则将出现编译错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值