Java枚举列表和枚举

时间:2019-04-29 03:17:58  来源:igfitidea点击:

在某些逻辑情况下,变量的值必须限制在解决方案规范中定义的特定范围或集合内。假设我们必须开发一个管理车辆的Java应用程序,并且引擎类型必须从{galle、DIESEL、HYBRID、ELECTRICAL}集合中获取一个值。我们可以将引擎类型定义为 字符串int,并且每次输入值时都可以进行验证。对于字符串,可以将输入值与“汽油”、“柴油”等进行比较。对于整数,可以假设汽油是1,柴油是2,…,并基于此逻辑检查值。这是一种可能的方法,但这并不好,因为你很容易犯错误,而且你会使一个非常简单的过程复杂化。

从Java5.0开始,该框架允许程序员定义一组预定义的值、一个 枚举值列表枚举值,从而为这个问题提供了一个更优雅的解决方案。此外,程序员可以定义变量,这些变量的值将限制为枚举列表中的一个。当程序员试图用 枚举之外的值初始化变量时,编译器将通过生成错误来忽略这一点。 枚举列表(Enumerated lists)枚举(enums)可以看作是一种新的数据类型,对于其可能的值有一个定义的限制。

在枚举列表中,无论是C语言、C++语言还是C# 语言,都是实现这个工具的。

如何定义和使用枚举

最常用的声明枚举的语法是

enum EnumName {constant1, constant2, ..., constantN};  //注意结尾的;(分号)是可选的

枚举可以在下面几种情况中声明

  • 独立地、全局地作为自己的类;
  • 在另一个类中
  • 不在方法中;

回到车辆场景,最佳解决方案是为发动机类型声明一个 enum,如下所示:

//在它自己的类中定义的枚举列表
// 最后的分号 ; 是可选的
enum EngineTypes{DIESEL,GASOLINE,HYBRID,ELECTRIC}

class Vehicle
{
    //在类中定义的枚举列表
    protected enum ColorTypes{RED, GREEN, BLUE, WHITE};

    //EngineTypes 实例变量
    public EngineTypes engine;
    //ColorTypes 实例变量
    public ColorTypes color;
}

定义枚举时请记住:

枚举符号或常量通常根据Sun命名约定用大写字母(如DIESEL、GASOLINE等)定义;
枚举符号不是int或string;
全局声明的枚举只能定义为default或public(而不是private或protected),但在后一种情况下,可以定义为它们自己的.java文件(与类的规则相同);
在另一个类内声明的枚举可以有访问修饰符(private、public、protected、default),这些修饰符控制其父类外的可见性

如前所述,枚举用于控制变量的可能值。因此,如果要初始化引擎实例变量值,我们必须只使用EngineTypes枚举中的常量。对于在其他类中声明的枚举,程序员必须使用完全限定名,包括父类名。

public class Main {
    public static void main(String[] args) {
        Vehicle v = new Vehicle();
        v.engine = EngineTypes.DIESEL;

        //compiler errors:
        //v.engine = "DIESEL";  //error
        //v.engine = 1;         //error

	//类指定的完全限定名 class_name.enum_name.symbol
        v.color = Vehicle.ColorTypes.GREEN;
        //compiler error
        //v.color = ColorTypes.GREEN; //error
    }
}

枚举的一个有趣的特性是,它的符号可以很容易地将字符串值转换为符号。

System.out.println("汽车引擎为:"+v.engine);

        String engineType = EngineTypes.ELECTRIC.toString();
        System.out.println("引擎为: "+engineType);

输出:

汽车引擎为:DIESEL
引擎为:ELECTRIC

Java中枚举是类的情况

在其他语言中,如C或C++枚举是符号的集合,这些符号具有唯一的数字ID。这个描述不能应用在这里,因为在java枚举中是类,它们的符号是EnUM类的静态和常数实例变量。

由于枚举是类,这意味着我们可以添加实例变量,方法,构造函数到枚举(除了其符号之外):

如果我们希望在枚举中存储的不仅仅是符号,也就是其他值或一些内部处理例程。

回到车辆场景,让我们更复杂一点:

  • 我们需要为每个引擎类型关联一个变量,该变量将存储一个唯一的数字代码;
  • 我们通过将代码属性定义为private来保护它;
  • 我们定义一个方法,该方法将返回引擎类型代码以便只读取它;
  • 我们需要一个构造函数,因为每个引擎类型符号都有自己的唯一代码。

根据以前的规则,EngineTypes枚举如下所示:

//为自己类定枚举列表
// 最后的;是可选的
enum EngineTypes{
    //每个符号都是通过调用构造函数来创建的
    DIESEL(10),GASOLINE(20),HYBRID(30),ELECTRIC(40);

    //code的枚举实例变量
    private int code;

    //枚举 构造函数
    EngineTypes(int codeValue){
        code = codeValue;
    }

    //枚举方法
    public int getCode(){
        return code;
    }
// 
}

尽管EngineTypes enum看起来像一个类,但它不是一个普通的类,因为:

不允许对构造函数使用公共和受保护的访问修饰符。 我们不能通过直接调用构造函数(即new EngineTypes(30))来创建实例; 枚举符号必须是枚举列表中的第一个声明;我们只能在定义枚举符号(即DIESEL(10))时调用构造函数,即使语法不同,更类似于C++,也可以重载枚举构造函数并用任意数量的参数定义它们;

在这种情况下,枚举符号的行为类似于对象,我们可以调用类方法。 EngineTypes类型的变量表示对常量对象的引用。

System.out.println("引擎类型: " + v.engine +
                ", code = "+v.engine.getCode());

输出:

引擎类型: DIESEL, code = 10

如何遍历枚举值

每个枚举列表提供一个静态方法 values(),用于遍历枚举常量。

System.out.println("引擎值:");
        for(EngineTypes et : EngineTypes.values())
        {
            System.out.println(et + " ,code = "+et.getCode());
        }

结果:

引擎值:
DIESEL ,code = 10
GASOLINE ,code = 20
HYBRID ,code = 30
ELECTRIC ,code = 40

什么是常量特定的类体

枚举是表示有限值集的常量对象列表。这些价值观在非常具体的情况下是重要的。尽管枚举是类,程序员还是会让事情变得非常简单,因为枚举是一种特殊类型的类,具有非常特定的角色。大多数枚举方法(如果有的话)都很简单(比如getter和setter),并且提供了枚举符号的通用解决方案。

如果存在需要返回属性值以上的情况,建议创建一个新类并重新考虑解决方案体系结构或实现简单的解决方案。

枚举提供了用于确定引擎类型是否污染的方法;

如果我们分析发动机的类型,我们可以看到除了电动的以外,所有的发动机都是污染源。因此,解决方案是定义一个测试引擎类型的方法:

如我们所见,对于枚举来说,代码变得有点太复杂了。为了简单起见,Java提供了另一种解决方案,称为[特定于常量的类体]。它表示程序员可以为特定枚举常量或符号定义特定方法实现的情况。

总结

  • 枚举是一个符号列表,这些符号不是字符串、整数……而是常量值;
  • 枚举类型变量只能用枚举符号赋值;
  • 声明枚举时,结尾分号(在结束的})是可选的;
  • 枚举是类,可以包含属性、方法和构造函数;
  • 枚举可以独立声明,全局作为它们的自己的类,在另一个类中,但不在方法中;
  • 不能通过直接调用构造函数来创建实例;只能在定义枚举符号(即DIESEL(10))时调用构造函数;
  • 可以重载枚举构造函数并用任意数量的参数定义它们;
  • 枚举静态方法, **values(),可用于遍历枚举常量;
  • 枚举符号可具有用于重写泛型方法的特定于常量的类体;