- 浏览: 278775 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
付小忠:
牛逼,解释到了点子上.
JAVA CAS原理深度分析 -
yhxf_ie:
csdn那些鬼转载都不注明出处的,这应该是原文了。
JAVA CAS原理深度分析 -
qq569349370:
终于找到一篇说得比较清楚的了,其他好多都是扰乱视听
JAVA CAS原理深度分析 -
lovemelong:
nice
JAVA CAS原理深度分析 -
Tyrion:
写的不错!
JAVA CAS原理深度分析
对于以下文 章需要指出的是,枚举类中的变量不一定是final的,可以被多次赋值,并且是全局的,可以用作设置全局变量。
对枚举类型印象大多来自于C 语言,在 C 语言中,枚举类型是一个 HardCode (硬编码)类型,其使用 价值并不大。因此,在 Java 5 之前,枚举是被抛弃的。然而 Java 5 以后的发现版本开始对枚举进行支持,枚举的引入给 Java 世界带来了争议。
笔者比较赞同引入枚举,作为一门通用的静态编程语言,应该是海纳百川的 (因此笔者赞成闭包进入Java 7 ), 多途径实现功能。
如果您不了解枚举的用法,建议参考笔者以前网络资源,了解基本的用法。 地址为: http://mercyblitz.blog.ccidnet.com/blog-htm-do-showone-uid-45914-type-blog-itemid-189396.html
枚举是一种特殊的(受限制的)类,它具有以下特点:
- 可 列性
- 常 量性
- 强 类型
- 类 的特性
留下一个问题-怎么利用这些枚举特点,更好为设计服务呢?根据这些特 点,下面向大家分别得介绍设计技巧。
一、 可 列性
在设计中,必须搞清楚枚举 使 用场景 。 枚 举内部成员都是可列的,或者说固定的。这种硬编码的形式,看上去令人觉得不自在,不过这就是枚举。如果需要动态(不可列)的成员话,请不好使用枚举。
JDK提供不少良好的可列性设计枚举。比如时间单位 java.util.concurrent.TimeUnit 和 线程状态枚举 java.lang.Thread.State 。
假设有一个游戏难度枚举,有三种难度NORMAL , MEDIUM, HARD
- /**
- * 游戏中的难度枚举:NORMAL , MEDIUM, HARD
- *
- * @author mercyblitz
- */
- public enum Difficulty {
- NORMAL, MEDIUM, HARD //注意:枚举成员命名,请使用 英文大写形式
- }
/** * 游戏中的难度枚举:NORMAL , MEDIUM, HARD * * @author mercyblitz */ public enum Difficulty { NORMAL, MEDIUM, HARD //注意:枚举成员命名,请使用英文大写形式 }
如果要添加其他成员,只能通过硬编码的方法添加到枚举类。回到枚举 Difficulty,低版 本的必定会影响二进制兼容性。对于静态语言来说,是无法避免的,不能认为是枚举的短处。
二、 常 量性
之所以定性为常量性,是因为枚举是不能改变,怎么证明 成员其不变呢?利用上面的Difficulty枚举为例,一段简单的代码得到其原型,如下:
- package org.mercy.design.enumeration;
- import java.lang.reflect.Field;
- /**
- * Difficulty 元 信息
- * @author mercy
- */
- public class MetaDifficulty {
- public static void main(String[] args) {
- MetaDifficulty instance = new MetaDifficulty();
- // 利用反射连接其成员的特性
- Class<Difficulty> classDifficulty = Difficulty.class ;
- for (Field field : classDifficulty.getFields()) {
- instance.printFieldSignature(field);
- System.out.println();
- }
- }
- /**
- * 打 印字段 签名(signature)
- *
- * @param field
- */
- private void printFieldSignature(Field field) {
- StringBuilder message = new StringBuilder( "字段 " )
- .append(field.getName())
- .append(" 的签名:" )
- .append(field.toString())
- .append("\t" );
- System.out.print(message);
- }
package org.mercy.design.enumeration; import java.lang.reflect.Field; /** * Difficulty 元信息 * @author mercy */ public class MetaDifficulty { public static void main(String[] args) { MetaDifficulty instance = new MetaDifficulty(); // 利用反射连接其成员的特性 Class<Difficulty> classDifficulty = Difficulty.class; for (Field field : classDifficulty.getFields()) { instance.printFieldSignature(field); System.out.println(); } } /** * 打印字段 签名(signature) * * @param field */ private void printFieldSignature(Field field) { StringBuilder message = new StringBuilder("字段 ") .append(field.getName()) .append(" 的签名:") .append(field.toString()) .append("\t"); System.out.print(message); } }
printFieldSignature 方 法输出枚举 Difficulty的 字段,其结果为:
字段 NORMAL 的签 名:public static final org.mercy.design.enumeration.Difficulty org.mercy.design.enumeration.Difficulty.NORMAL
字段 MEDIUM 的签 名:public static final org.mercy.design.enumeration.Difficulty org.mercy.design.enumeration.Difficulty.MEDIUM
字段 HARD 的签 名:public static final org.mercy.design.enumeration.Difficulty org.mercy.design.enumeration.Difficulty.HARD
这个结果得出了两个结论,其一,每个枚举成员是枚举的字段。其二,每个成员都被 public static final。 凡是 static final 变 量都是 Java 中的 “常量”,其保存在常量池中。根据其常量性和命名规则,建议全大写命名每个枚举的成员(前面提到)。
常量性提供了数据一致性,不必担心被被其他地方修改,同时保证了线程安全。因此在设计过程中,不必担心线程安全问题。
枚举类型是常量,那么在判断是可以使用== 符号来做比较。可是如果枚举成员能够克隆 (Clone) 的话 , 那么 == 比较会失效,从而一致性不能得到保证。如果按照类的定义方法,考虑枚举的话,那么枚举类是集成了 java.lang.Object 类,因此,它继承 了 protected java.lang.Object clone() 方法,也就是说支持 clone ,虽然需要通过反射的手段去调用。 Java 语言规范提到,每个枚举继承了 java.lang.Enum<E> 抽象基类。
提供一段测试代码来验明真伪:
- /**
- * 指 定的类是枚举java.lang.Enum<E>的子类吗?
- *
- * @param klass
- * @return
- */
- private boolean isEnum(Class<?> klass) {
- Class<?> superClass = klass.getSuperclass();
- while ( true ) { // 递归 查找
- if (superClass != null ) {
- if (Enum. class .equals(superClass))
- return true ;
- } else {
- break ;
- }
- superClass = superClass.getSuperclass();
- }
- return false ;
- }
/** * 指定的类是枚举java.lang.Enum<E>的子类吗? * * @param klass * @return */ private boolean isEnum(Class<?> klass) { Class<?> superClass = klass.getSuperclass(); while (true) { // 递归查找 if (superClass != null) { if (Enum.class.equals(superClass)) return true; } else { break; } superClass = superClass.getSuperclass(); } return false; }
客户端代码调用: instance.isEnum(Difficulty. class ) ; 结 果返回true ,那么证明了 Difficulty 枚 举继承了java.lang.Enum<E> 抽象基类。
那么java.lang.Enum<E> 有没有覆盖 clone 方法呢?查看一下源代码:
- /**
- * Throws CloneNotSupportedException. This guarantees that enums
- * are never cloned, which is necessary to preserve their "singleton"
- * status.
- *
- * @return (never returns)
- */
- protected final Object clone() throws CloneNotSupportedException{
- throw new CloneNotSupportedException();
- }
/** * Throws CloneNotSupportedException. This guarantees that enums * are never cloned, which is necessary to preserve their "singleton" * status. * * @return (never returns) */ protected final Object clone() throws CloneNotSupportedException{ throw new CloneNotSupportedException(); }
很明显,java.lang.Enum<E> 基类 final 定 义了 clone 方法, 即枚举不支持克隆,并且 Java doc 提到要保持单体性。那么这也是面向对象设计的原则之一 - 对于保持单态性的对象而 言,尽可能不支持或者不暴露clone 方 法。
三、 强 类型
前面的两个特性,在前Java 5 时代,利用了常量字段也可以完成需 要。比如可以这么设计Difficulty类的字段,
- public static final int NORMAL = 1 ;
- public static final int MEDIUM = 2 ;
- public static final int HARD = 3 ;
public static final int NORMAL = 1; public static final int MEDIUM = 2; public static final int HARD = 3;
这么设计有一个缺点-弱类型,因为三个字段都是int原生型。
比如有一个方法用于设置游戏难度,定义如下:
- public void setDifficulty( int difficulty)
public void setDifficulty(int difficulty)
利用int类型作为参数,可能会有问题-如果参数在NORMAL,MEDIUM,HARD之外int数是可以接受的。利用规约的方法可以避免这个问题,比 如设计范围检查:
- /**
- * 设置游戏难度
- * @param difficulty 难 度数
- * @throws IllegalArgumentException
- * 如 果参数不是 NORMAL、MEDIUM和Hard其中一个,那么报出IllegalArgumentException
- */
- public void setDifficulty( int difficulty)
- throws IllegalArgumentException
/** * 设置游戏难度 * @param difficulty 难度数 * @throws IllegalArgumentException * 如果参数不是 NORMAL、MEDIUM和Hard其中一个,那么报出IllegalArgumentException */ public void setDifficulty(int difficulty) throws IllegalArgumentException
在可能实现方法中,通过三次成员比较,这样比较笨拙和憋足。
如果您在使用Java 5以前版本的话,作者提供一个较好的实现方法:
- package org.mercy.design.enumeration;
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.Set;
- /**
- * Difficulty JDK1.4 实现 Difficulty枚举
- * @author mercy
- */
- public class Difficulty14 {
- //枚举字段
- public static final int NORMAL = 1 ;
- public static final int MEDIUM = 2 ;
- public static final int HARD = 3 ;
- private final static Set difficulties;
- static {
- // Hash 提供快速查找
- HashSet difficultySet = new HashSet();
- difficultySet.add(Integer.valueOf(NORMAL));
- difficultySet.add(Integer.valueOf(MEDIUM));
- difficultySet.add(Integer.valueOf(HARD));
- //利用不变的对象是一个好的设计实践
- difficulties= Collections.unmodifiableSet(difficultySet);
- }
- /**
- * 设 置游戏难度
- * @param difficulty 难 度数
- * @throws IllegalArgumentException
- * 如果参数不是NORMAL、 MEDIUM和Hard其中一个,那么报出 IllegalArgumentException
- */
- public void setDifficulty( int difficulty)
- throws IllegalArgumentException {
- if (!difficulties.contains(Integer.valueOf(difficulty)))
- throw new IllegalArgumentException( "参数错误" );
- //设置难度...
- }
- }
package org.mercy.design.enumeration; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Difficulty JDK1.4实现 Difficulty枚举 * @author mercy */ public class Difficulty14 { //枚举字段 public static final int NORMAL = 1; public static final int MEDIUM = 2; public static final int HARD = 3; private final static Set difficulties; static { // Hash 提供快速查找 HashSet difficultySet = new HashSet(); difficultySet.add(Integer.valueOf(NORMAL)); difficultySet.add(Integer.valueOf(MEDIUM)); difficultySet.add(Integer.valueOf(HARD)); //利用不变的对象是一个好的设计实践 difficulties= Collections.unmodifiableSet(difficultySet); } /** * 设置游戏难度 * @param difficulty 难度数 * @throws IllegalArgumentException * 如果参数不是NORMAL、MEDIUM和Hard其中一个,那么报出IllegalArgumentException */ public void setDifficulty(int difficulty) throws IllegalArgumentException { if(!difficulties.contains(Integer.valueOf(difficulty))) throw new IllegalArgumentException("参数错误"); //设置难度... } }
在上面的代码中,尽管提供了范围检查,不过参数范围还是巨大(可以 说是无数),并且是运行时检查。因为 setDifficulty 的 参数是 int的, 客户端调用时候,编译器可以接受 int 以及范围更小的 short 、 byte 等类型。那么违反了 一个良好的实践 -在面向对象 设计中,类型范围最好在编译时确定而非运行时。
另一个良好的面向对象实践 -利用对象类型,而不是原生型(如果编程语言支持的话)。 那 么,如果使用java.lang.Integer 取 代 int 类型,并且 Integer 是 final 类,没有必要担心多态的情况下,不就可 以提供强类型吗?的确,提供了强类型约束,并且更好的锁定类型范围(因为是 final 的)。可是, Integer 的范围在一定程度上,认为是无限的,同时不支持 swtich 语句( 仅支持 int 、 short 、 byte 和 Java 5 枚举类型)。因此 Integer 还是不合适的。
枚举的常量性和可列性,在Difficulty 场景中尤其适合。
四、 类 的特性
已知每个枚举都继承了java.lang.Enun<E> 基类,其既有常量性,同时也有类的特点。尽管它是一种被限制的类,比如name和ordinal字段状态都是有JVM处理的。不过开发人员可以充分的利用 类的特点,作出优美的设计。
枚举既然也是类,那么也遵循类的设计。通过扩张 Difficulty 类, 面向对象的方式来设计枚举。
1. 封 装设计
如果有一个 需求 - Difficulty 持 久化,把其存入 d ifficult ies数 据库表中,并且提供一个唯一的 id 整型值。面向对象的封装,枚举也 适用。示例如下:
- public enum Difficulty {
- // 注意:枚举成员命名,请使用英文大写形式
- NORMAL(1 ), MEDIUM( 2 ), HARD( 3 );
- /**
- * final 修饰字段是一个良好的实践。
- */
- final private int id;
- Difficulty(final int id){
- this .id=id;
- }
- /**
- * 获 得ID
- * @return
- */
- public int getId() {
- return id;
- }
- }
public enum Difficulty { // 注意:枚举成员命名,请使用英文大写形式 NORMAL(1), MEDIUM(2), HARD(3); /** * final修饰字段是一个良好的实践。 */ final private int id; Difficulty(final int id){ this.id=id; } /** * 获得ID * @return */ public int getId() { return id; } }
通过调用getId 方法可以获取枚举成员的 ID 值。
2. 抽 象设计
在不同的游 戏难度级别中,不同任务的难度值不同(大多数情况是通过值来表示,而非枚举对象本身)。以Difficulty为例,定义一个抽象的方法,计算难度值。
- /**
- * 获 取不同任务的难度值
- *
- * @param mission
- * @return
- * @throws IllegalArgumentException
- * 如 果<code>mission</code> 为负数时。
- */
- public abstract int getValue( int mission) throws IllegalArgumentException;
/** * 获取不同任务的难度值 * * @param mission * @return * @throws IllegalArgumentException * 如果<code>mission</code> 为负数时。 */ public abstract int getValue(int mission) throws IllegalArgumentException;
3. 多 态设计
Difficulty 枚举中定义抽象方法getValue,那么其子类必须实现这个方法。不过枚举不能被继承,也不能继承其他类,除了默认额 java.lang.Enum<E>类以外。因此枚举是一个final的版本,不能实现抽象方法?
枚举的特殊 在此,枚举虽然不能显示地利用extends关键字继承,不过它的每个成员都是自己的子类。那么以Difficulty为例,其类层次关系 为:java.lang.Enum<E> -> Difficulty -> HARD。这么看来,每个枚举成员相当于定了一个 final的类内置类。
回到 Difficulty枚举,实现抽象方法如下:
- NORMAL( 1 ) {
- @Override
- public int getValue( int mission)
- throws IllegalArgumentException {
- return mission + this .getId();
- }
- },
- MEDIUM(2 ) {
- @Override
- public int getValue( int mission)
- throws IllegalArgumentException {
- return mission *
相关推荐
本手册全面讲解了ST语言的基本原理、规则以及使用实例,旨在帮助读者在对编程不熟悉的情况下,也能快速理解和掌握ST语言。 1. **ST基本原理** - **语言描述**:ST语言基于结构化文本,允许程序员使用类似于Pascal...
6. 枚举(ENUM)和集合(SET)类型:ENUM用于定义只能取预设值之一的字段,SET用于定义可以取多个预设值的字段。 二、MySQL操作 1. 创建数据库:使用CREATE DATABASE语句创建新的数据库。 2. 使用数据库:通过USE语句...
对于【第9章:枚举&注解(day14)】的学习资料,可能是某个课程或教程的一部分,涵盖了这两个主题的深入讲解和实践示例。学习者可以通过这份资料深入了解枚举和注解的用法,以及如何在实际项目中应用这些概念,提升...
13. **枚举(Enum)**:讲解枚举类型的特点和使用,包括枚举常量、枚举类、枚举开关等。 14. **Lambda表达式**:介绍Java 8引入的函数式编程元素,包括函数接口、lambda表达式和方法引用来简化代码。 15. **Stream...
在"C#全程讲解"这个课程中...总的来说,"C#全程讲解"提供了全面的C#编程知识,涵盖了从基础到进阶的主题,是学习和提升C#技能的理想资源。通过深入理解和实践这些概念,开发者可以高效地构建健壮且灵活的.NET应用程序。
11. **枚举类型**:Enum的使用,枚举常量的定义,以及与枚举相关的类和方法。 12. **泛型**:泛型的概念,类型通配符,泛型方法,以及在集合中的应用。 13. **JDBC**:数据库连接,预编译语句,结果集处理,事务...
8. 列举:介绍了Swift中枚举(enum)的定义和使用,包括带有原始值和关联值的枚举类型。 9. 类和结构:讲解了Swift中面向对象编程的基础概念,包括类和结构体的定义、继承、构造器(initializers)、析构器...
3. 枚举(Enum):比常量更强大的数据类型,支持枚举类。 4. Lambda表达式:简化函数式编程,使代码更加简洁。 5. 反射(Reflection):在运行时动态获取类的信息并操作类的对象。 四、异常处理 详述Java的异常处理...
本章主要讲解如何在C语言中定义和使用结构体变量,以及结构体在数组、指针和链表中的应用,同时也涵盖了共用体类型和枚举类型。 9.1 定义和使用结构体变量 结构体是一种自定义的数据类型,它允许我们将多种不同...
枚举(Enum)是Swift中一种特殊的类,文档中对枚举的语法、匹配枚举值使用Switch语句、关联值以及原始值等方面都做了讲解。类(Class)和结构体(Struct)在Swift中是值类型和引用类型的代表,文档中对它们的对比、...
`VIDIOC_ENUM_FRAMESIZES` 和 `VIDIOC_ENUM_FRAMEINTERVALS` 分别用于枚举可选的帧尺寸和帧间隔,这对于调整视频录制或播放的分辨率和帧率至关重要。 `VIDIOC_ENUMINPUT` 和 `VIDIOC_ENUMOUTPUT` 用于枚举视频输入...
"第十九讲 枚举与注解"涵盖了枚举类型(enum)和注解(annotation)。枚举是Java中一种特殊的类,用于定义一组固定的常量。注解提供了一种元数据的方式,可以向编译器、解释器或其他工具提供信息,用于代码分析、...
作者会讲解如何使用枚举类型(enum)以及注解(annotation),这些都是Java SE 5.0引入的新特性。此外,集合框架是Java编程中的重要工具,03部分会详细阐述ArrayList、LinkedList、HashSet、HashMap等集合类的使用和...
总的来说,《JAVA 5.0 TIGER程序高手秘笈》这本书全面讲解了Java 5.0的新特性,包括泛型、枚举、注解、并发工具、增强的循环和类型系统等,是Java开发者进阶学习的重要参考资料。通过深入学习和实践,开发者可以提升...
8. **Java集合高级特性**:包括枚举类型(enum)、匿名内部类、Lambda表达式和函数式接口,这些都是Java 5及以后版本引入的重要特性,极大地提高了代码的简洁性和可读性。 9. **网络编程**:Java的Socket编程用于...
- 枚举(Enum):理解枚举类型的特性和使用场景。 本教程PPT1将详细阐述以上知识点,并通过实例演示和习题练习帮助学习者巩固理解。在深入学习Java的过程中,建议结合实际项目实践,以加深对理论知识的应用和掌握...
C++中提供了基本的内置数据类型,包括整型(如int、char)、布尔型(bool)、指针类型(type *)、空类型(void)以及结构体(struct)、联合(union)、枚举(enum)和类(class)。此外,还有一些修饰符,如long、...
"05枚举、结构体、访问修饰符.pdf"则涉及到C#中的枚举(Enum)、结构体(Struct)和访问修饰符(Access Modifiers)。枚举是一种强类型的常量集合,结构体则是用户定义的值类型。访问修饰符如public、private、...
9. **其他高级特性**:如注解(Annotation)、泛型(Generics)、枚举(Enum)、Lambda表达式和Stream API,这些都是Java语言的重要特性,书中会详细介绍它们的用法和实际应用。 通过阅读《Java核心技术 卷II 高级...
同时,Java的枚举类型(enum)和枚举常量集也成为了一种更安全、更优雅的替代常量的方式。 Java的模块系统(Jigsaw项目)是Java 9引入的,旨在解决大型项目中的依赖管理和提升性能。模块化可以让开发者更好地组织和...