java枚举的特点_Java中有些好的特性(二):枚举

前言

我在写上一篇时,开始选了一个很土的名字“Java超过C#的地方”,然后引起了某些同学的不满,后来修改了个名。我在这里再次申明一下,我没有贬低任何语言之意,纯粹是从一个.NET程序员的角度去看Java,看看是不是有些什么在开发中觉得比较“爽”的东西。务必请用专业的态度来比较各种技术的长短。

Java的枚举是一个“class”

Java的早期版本时没有enum的,大家都用interface里加常量的方式实现,Java 1.5版本之后添加了对enum的支持。

Java认为类C的枚举不是类型安全的(type safe),所以Java中没有枚举,Java的枚举就是类(Enum Class),只是用了一个enum代替class而已(虽然.NET里在MSIL层面枚举最终也是一种“class”)。因为Java的枚举是类,所以就带来一些与C#中的枚举有趣的不同点,比如可以添加方法,可以添加属性。请看下面的Java代码:

1: public enum Role{

2: Admin("管理员"),

3: Owner("所有者"),

4: Creator("创建者");

5:

6: private String displayName;

7:

8: Role(String displayName){

9: this.displayName = displayName;

10: }

11:

12: public String getDisplayName(){

13: return this.displayName;

14: }

15: }

Java的枚举居然可以这么写!枚举里可以有方法。这里的Admin,Owner,Creator实际上是Role类的常量,调用Role(String)构造器,但是Java不允许你将enum的构造器设为public,由Java自己内部调用。

有人可能会问这样有什么用处呢?比如上面这段代码,建一个枚举表示系统中的所有角色,为了用户友好性,数据库里我们保存角色名字,但是在系统界面上我们要显示一个更具描述性的名字,而且假如我们的系统需要多语言化,那么在不同的语言平台上的界面上我们的系统应该显示不同的描述性短语(注意:.NET中的枚举是不能国际化的),比如下面的界面:

1d5985a25dcb3f0980fd244b14f9808b.png

3596daf32bec78b4f28e8095d4d61de8.png

那我们就可以这样做:

1: public enum Role{

2: Admin("role-admin"),

3: Owner("role-owner"),

4: Creator("role-creator");

5:

6: private String displayName;

7:

8: Role(String displayName){

9: this.displayName = displayName;

10: }

11:

12: public String getDisplayName(){

13: return Resource.get(this.displayName);

14: }

15: }

我们这里getDisplayName的时候调用一个国际化的API,通过枚举构造器里传入的参数作为key获取国际化的表示。

Java的enum是类型安全、版本安全的

这样一说好像C#的enum不是类型安全的一样,哼!嗯,某种角度上来说C#(本文以C#指代整个.NET平台)的枚举真的不是类型安全的。比如下面的代码:

1: using System;

2: public enum Role:short

3: {

4: Admin,Owner,Creator

5: }

6:

7: public class Program

8: {

9: public static void Main(String[] args)

10: {

11: byte i = (byte)Role.Owner;

12: }

13: }

即使我们给C#的enum指定了underlying type,但是我们还是可以将其任意的与基本类型进行转换。而且这种转换是静悄悄地进行的,编译器和运行时都不会提醒我们。

C#的enum完全是一个常量,所以跟C#的const一样还会带来版本的问题。比如A程序集定义了一个枚举Role,B程序集引用A程序集,使用Role,实际上在运行时B程序集不再需要A程序集了(大家知道什么原因吧)。这样如果A程序集修改了Role,比如修改了枚举常量的顺序:从Admin,Owner,Creator变为Admin,Creator,Owner。而B程序集没有重新编译,这个时候就会出现问题。

C#中实现Enum class

实际上Enum Class是一种模式,只是java的enum将这种模式放到了语言中,我们在C#里一样可以实现:

1: public sealed Class Role

2: {

3: public static readonly Role Admin = new Role("role-admin");

4: public static readonly Role Owner = new Role("role-owner");

5: public static readonly Role Creator = new Creator("role-creator");

6:

7: private String displayName;

8:

9: private Role(String displayName)

10: {

11: this.displayName = displayName;

12: }

13:

14: public String DisplayName

15: {

16: get

17: {

18: Resource.Get(this.displayName);

19: }

20: }

21: }

只是实现起来比java的默认实现繁琐一点而已,毕竟那是人家语言的first class。

位标记

如果在C#的enum上添加[Flags]的特性话,这个enum就不再是enum了,就变成了位标记。位标记这东西在实现某些功能时确实非常滴方便,比如一个文件的属性:只读,只写,可读写,比如权限控制系统等等。Java的枚举就不能添加这么一个annotation了,不过Java有个EnumSet,我们借助这个API实现位标记同样的功能。

后记

Java的enum与C#的enum各有特色,Java的enum更灵活一些,C#的enum更轻型一些,但是使用时请注意C#的enum的一些问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java ,动态类加载是指在程序运行时动态地加载类,而不是在编译时加载。这种方式可以使程序更加灵活,可以根据不同的需求加载不同的类。 Java 枚举Enum)也可以通过动态类加载的方式来实现。枚举是一种特殊的类,可以包含常量、方法和字段。在 Java 枚举常量是在编译时确定的,但是可以通过动态类加载来动态地加载枚举类。 下面是一个动态加载枚举的示例代码: ```java import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class DynamicEnumLoader { public static void main(String[] args) throws Exception { // 枚举类的路径 URL url = new URL("file:/path/to/enum/classes"); // 创建类加载器 URLClassLoader classLoader = new URLClassLoader(new URL[]{url}); // 加载枚举类 Class<?> enumClass = classLoader.loadClass("com.example.MyEnum"); // 获取枚举常量 Object[] enumConstants = enumClass.getEnumConstants(); // 调用枚举方法 Method method = enumClass.getMethod("getValue"); for (Object obj : enumConstants) { String value = (String) method.invoke(obj); System.out.println(value); } } } ``` 在上面的示例,我们创建了一个 URLClassLoader 对象,将枚举类的路径传入其。然后使用该类加载器加载了 MyEnum 枚举类。最后,通过反射的方式调用了 getValue 方法,获取枚举常量的值。 需要注意的是,动态加载的枚举类必须要和程序的类在同一个类加载器,否则会出现 ClassCastException 异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值