Java枚举类型

在Java中,枚举类型使用enum关键字来定义。枚举类型是一种特殊的数据类型,用于定义和使用一组常数。如果把enum类型当做一种特殊的类(class),那么它的实例必须是预先定义好的常数当中的一个。当我们要使用一组固定的常数时,使用枚举类型(当然,在接口当中定义静态常量也是可以的),例如:

<span style="font-family:Microsoft YaHei;font-size:12px;">/**
 * @author Brandon B. Lin
 *
 */
public enum Direction {
	 NORTH, SOUTH, EAST, WEST
}
</span>
上面的代码定义了一个枚举类型,有四个常量。每个枚举常量都是枚举类型的实例对象,被隐式地声明为该枚举类型的public、static、final成员。有了枚举类型之后,我们就可以创建枚举类型的变量(对比数组类型的变量)。下面的代码简单地使用了这个枚举类型:

<span style="font-family:Microsoft YaHei;font-size:12px;">/**
 * @author Brandon B. Lin
 *
 */
public class TestEnum {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Direction direction = Direction.EAST; //枚举类型变量
		switch (direction) {
		case EAST:
			System.out.println("east");
			break;

		case NORTH:
			System.out.println("north");
			break;
		
		default:
			break;
		}

	}

}</span>
注意到在direction = Direction.EAST这个语句当中,使用EAST这个枚举类型实例的时候,格式为Direction.EAST,也就是EAST是DIrection枚举类型的实例,但同时它又以public static final成员的身份存在。但是在case语句中,我们没有使用枚举类型名,而是直接使用EAST或者NORTH,之所以可以这么做,是因为switch(direction)已经隐式地指定了case常量的枚举类型,也就是通过direction的类型来判断case后面常量的类型。一点题外话,swith除了可以使用byte、char、short、int类型外,还可以使用String类型和枚举类型。

理解枚举类型(enum type)一种比较直观的方式就是把它当做一种特殊的class,特殊之处在于它的实例必须是常数组中的某个值。既然把枚举类型当做一种特殊的类,那么它应该也可以定义域和方法,就像一般的类一样,答案是肯定的。在Java的enum类型中,可以定自己的域和方法。虚拟机创建一个枚举类型的时候,自动加入了一些常用的方法,虽然这些方法没有在java.lang.Enum的API列出来(下面会说的所以enum类型都继承自Enum)。比如,有一个静态的方法values,它返回一个数组,其中数组的元素为定义枚举类型的时候指定的常数。这一方法常常和for-each结构一起使用,例如在上面的例子中,我们加入以下代码:

<span style="font-family:Microsoft YaHei;font-size:12px;">for(Direction d:Direction.values()) {
			System.out.println(d);
		}</span>

那么就会依次输出NORTH、SOUTH、EAST、WEST。枚举类型常量在println方法中,输出的是预先定义的常量的名称。


一点说明,所有的枚举类型都隐式地继承java.lang.Enum,虽然我们没有extends,又因为java使用单继承机制,所有enum类型不能再继承其他类,也不能被继承。所以使用Eclipse创建枚举类型的时候,你会发现你不能在初始的界面中添加父类,但是接口仍然可以,下面是创建枚举类型和创建class的界面对比:




除了预定义的values方法以外,因为继承自Enum,所以也继承了一些有用的方法,简单介绍如下:

<span style="font-family:Microsoft YaHei;font-size:12px;">public final String name()</span>
这个方法以字符串返回枚举类型实例(事先定义好的)的名字,也就是在定义枚举类型时给出的常数(如上面的EAST、NORTH)。例如,Direction.EAST.name()将返回“EAST”。

<span style="font-family:Microsoft YaHei;font-size:12px;">public final int ordinal()</span>
这个方法返回枚举类型实例在定义时候的索引为止(从0开始),例如,Direction.EAST.ordinal返回2.说明定义时候它排在第3位。

public static enum-type valueOf(String str)

这个方法返回枚举常量名为str的枚举类型实例(常量),例如Direction.valueOf("EAST")将返回EAST常量(注意EAST常量是枚举类型的一个实例)

final int compareTo(enum-type e)

调用这个方法的枚举常量类型必须和方法参数中的enum-type相同,否则无法比较。需要指出的是,这里比较的是枚举常量的ordinal(原始值),也就是位置索引。调用方法的常用在方法参数的前面返回负值,类似的,相等的时候返回0,在后面返回正值。

如果想要判断两个枚举常量是的相等性,可以使用equals方法,虽然equals可以将枚举类型与其他对象(不是该枚举类型的常量)进行比较,但是总是返回false,没有意义。只有当比较的两者属于同一枚举类型并且是相同的枚举常量,才返回true。当然,也可以用“==”来比较两个枚举类型常量。

我们可以为枚举类型提供构造函数、添加实例变量和方法,甚至可以实现接口。为了进一步说明枚举类型的域和方法,我们使用Java tutorial中的例子来说明。先上代码,再做说明:

<span style="font-family:Microsoft YaHei;font-size:12px;">public enum Planet {
	MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass() { return mass; }
    private double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage: java Planet <earth_weight>");
            System.exit(-1);
        }
        double earthWeight = Double.parseDouble(args[0]);
        double mass = earthWeight/EARTH.surfaceGravity();
        for (Planet p : Planet.values())
           System.out.printf("Your weight on %s is %f%n",
                             p, p.surfaceWeight(mass));
    }

}
</span>

首先是常量的定义,Java要求常量的定义必须首先出现,在域和方法之前。如果有域和方法,那么在常量定义全部结束的时候,必须使用分号(注意到如果没有域和方法时,分号可以省略)。在这个例子中,定义了几个常量,注意到定义常量的时候同时传递了参数,当常数被创建的时候,构造函数被调用一次,同时这些参数传递给构造函数。域和方法的定义和普通类完全相同,注意的是,所有的枚举类型实例都是实现定义好的,实例必须是这其中的一个,所以调用方法的时候也必须用这些常量来调用,如上面的EARTH.surfaceGravity().

枚举类型的构造器也可以被重载(overload),例如有如下两个构造器



枚举类型一般定义为top-level class,但是也可以定义为嵌套类,即在类内部定义枚举类型,此时,枚举类型自动变成static(即使没有显式声明),所以,枚举类型的实例(事先定义好的)不能访问外部类的实例成员(实例域和实例方法)。

public Apple() {...}
public Apple(int price) {...}

因此我们在定义枚举常量的时候,可以选择合适的构造器来创建常量,如:

enum Apple {
    AA(10), BB(8), CC,DD(1);
}


最后总结一下:

枚举类型是一种特殊的类,它可能的实例是事先定义好的,每个实例都有它自己的状态,并且这些实例自动被创建,以静态域(public static final)的方式保存。静态域的名字就是我们定义常量组时候设置的名字。十分重要的是,每个枚举常量都是定义它的类的对象!!在设计模式中,枚举类型是一种Flyweight模式,也就是类的实例只能是有限个事先定义好的其中一个。


转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值