句法糖句法糖,又译为糖衣语法,是英国计算机科学家彼得·J·兰丁发明的术语,指的是在计算机语言中加入的某种语法.这种语法对语言的功能没有影响,反而更方便程序员使用。一般来说,语法糖的使用可以增加程序的可读性,从而减少程序代码出错的几率。——摘自百度百科JVM本质上是不支持语法糖的,语法糖只存在于编译期。编译器在将.java源文件编译成.class字节码文件时,会进行句法糖解,还原最原始的基本语法结构。几乎所有我们熟悉的编程语言都含有语法糖,当然JAVA也不例外。JAVA中的语法糖包括条件编译、断言、switch支持String和枚举、可变参数、自动装箱/拆箱、枚举、内部类、泛型擦除、增强的for循环、lambda表达式、try-with-resources等。今天我们先来了解下枚举。枚举类JDK5提供了一个新的特殊类——枚举类,一般用于类对象有限且固定的场景,用于替代在类中定义常量的方式。枚举比常量更直观且类型安全。枚举类的使用很简单,用enum关键字定义,多个枚举变量直接用逗号分隔。我们先定义一个简单的枚举类OrderStatus.javapublicenumOrderStatus{//unpaid,paid,refunding,refundsuccessful,refundfailed;NO_PAY,PAY,REFUNDING,REFUNDED,FAIL_REFUNDED,;}在其他类中使用枚举变量时,只需要[类名.变量名],这和使用静态变量是一样的。另外,枚举类型可以保证JVM中只有一个常量实例,所以我们可以放心地使用“==”来比较两个变量。注意:枚举类的第一行必须是一个枚举项,最后一个枚举项后面的分号可以省略,但是如果枚举类还有其他东西,这个分号就不能省略。建议不要省略!枚举变量最好大写,多个单词用“_”隔开(例如:NO_PAY)。反编译我们可以先通过javac命令或IDEA的编译功能将OrderStatus.java编译成OrderStatus.class字节码文件,然后使用DJJavaDecompiler反编译器反编译.class文件。需要DJJavaDecompiler反编译器的可以私信阿Q获取!publicfinalclassOrderStatusextendsEnum{//该方法会返回一个包含所有枚举变量的数组,可以方便的循环使用。publicstaticOrderStatus[]values(){return(OrderStatus[])$VALUES.clone();}//根据传入的字符串转化为对应的枚举变量。//前提是传入的字符串与定义枚举变量的字符串相同,区分大小写。//如果传入不存在的字符串,会抛出异常。publicstaticOrderStatusvalueOf(Stringname){return(OrderStatus)Enum.valueOf(com/itcast/java/enumpack/OrderStatus,name);}privateOrderStatus(Strings,inti){super(s,i);}publicstaticfinalOrderStatusNO_PAY;publicstaticfinalOrderStatusPAY;publicstaticfinalOrderStatusREFUNDING;publicstaticfinalOrderStatus;statusREFUNDINGpublicstaticfinalOrderStatusFAIL_REFUNDED;privatestaticfinalOrderStatus$VALUES[];static{NO_PAY=newOrderStatus("NO_PAY",0);PAY=newOrderStatus("PAY",1);REFUNDING=newOrderStatus("REFUNDING",2);REFUNDED=newOrderStatus("REFUNDED",3);FAIL_REFUNDED=newOrderStatus("FAIL_REFUNDED",4);$VALUES=(newOrderStatus[]{NO_PAY,PAY,REFUNDED,REFUNDED,FAIL_REFUNDED});}}如源码所示:编译器会自动创建一个final类型的类继承了Enum类,所以不能继承枚举类。将自动生成私有构造函数。当然我们也可以定义一个构造函数,但是必须是private的,这样的对象就不能在别处声明了。枚举项会自动用publicstaticfinal修饰,定义为OrderStatus类型,并在静态代码块中初始化。并提供了values()和valueOf(Stringname)的静态方法。我们定义的枚举变量其实就是编译器自动为我们生成的构造函数。所有枚举类都是Enum的子类,枚举类可以实现一个或多个接口。EnumEnum是所有Java语言枚举类型的公共基类,实现了Comparable和Serializable接口。它包含final类型名和ordinal(这个枚举常量的序号,从0开始)属性,我们来看看它的方法protectedEnum(Stringname,intordinal);-施工方法;publicStringtoString();——返回name字段,即定义枚举变量的字符串;protectedfinalObjectclone();——抛出CloneNotSupportedException,确保枚举类永远不会被克隆;publicfinalClassgetDeclaringClass();——返回该枚举常量的枚举类型对应的类对象;protectedfinalvoidfinalize();——枚举类不能有finalize方法;readObject(ObjectInputStreamin);&readObjectNoData();——抛出InvalidObjectException异常,防止默认反序列化;扩展枚举类中的自定义属性值最好用privatefinal修饰,防止生成的set方法在使用时修改属性值,使代码更安全。可以在枚举类中自定义构造函数。必须将构造函数修改为私有的,以防止此类对象在别处声明。枚举类可以自定义方法,枚举项可以选择性的覆盖自定义方法。publicenumOrderStatus{NO_PAY("未支付",0),PAY("已支付",1){@OverridepublicvoidprintOrderStatus(){System.out.println("已支付");}},REFUNDING("正在退款",2),REFUNDED("退款成功",3),FAIL_REFUNDED("退款失败",4),;privatefinalStringname;privatefinalintstatus;privateOrderStatus(Stringname,intstatus){this.name=name;this.status=status;}publicvoidprintOrderStatus(){System.out.println("打印订单状态");}}publicclassEnumTest{publicstaticvoidmain(String[]args){OrderStatus.PAY.printOrderStatus();OrderStatus.NO_PAY.printOrderStatus();}}枚举类也可以有抽象方法,但枚举必须覆盖该方法。枚举类像普通类一样实现接口。实现接口时,需要实现接口的抽象方法,枚举类的不同对象也可以实现不同的行为。例子//定义一个接口publicinterfaceOrder{voidprintOrderStatus();}//枚举类实现了接口publicenumOrderStatusimplementsOrder{NO_PAY("Notpaid",0){@OverridepublicvoidprintOrderStatus(){System.out.println("Notpaid");}},PAY("已支付",1){@OverridepublicvoidprintOrderStatus(){System.out.println("已支付");}},REFUNDING("正在退款",2){@OverridepublicvoidprintOrderStatus(){System.out.println("退款成功");}},REFUNDED("退款成功",3){@OverridepublicvoidprintOrderStatus(){System.out.println("退款成功");}},FAIL_REFUNDED("退款失败",4){@OverridepublicvoidprintOrderStatus(){System.out.println("Refundfailed");}},;privatefinalStringname;privatefinalintstatus;privateOrderStatus(Stringname,intstatus){this.name=name;this.status=status;}}查看编译文件这时候,你会发现除了OrderStatus.class文件之外,还生成了多个.class文件:它们是OrderStatus.class中生成的匿名内部类文件。状态转换需求订单是电商项目中不可或缺的一部分,订单状态的转换也是我们经常讨论的问题。我们都知道订单状态的转换是有一定逻辑的,不能随意改变。例子:你想买一件商品,但是你只是把它加入了购物车,此时应该是未付款的。如果有转为退款状态的请求,系统会提示“状态转换失败,请先完成购买!”接下来,我们将使用枚举来完成对订单状态转换的限制。实现枚举类定义:publicenumOrderStatus{NO_PAY("Notpaid",0){@OverridepublicBooleancanChange(OrderStatusorderStatus){switch(orderStatus){casePAY:returntrue;default:returnfalse;}}},PAY("Paid",1){@OverridepublicBooleancanChange(OrderStatusorderStatus){//因为退款接口一般都会延迟,所以会先转换为“正在退款”的状态switch(orderStatus){caseREFUNDING:returntrue;default:returnfalse;}}},REFUNDING("ReturnIntheparagraph",2){@OverridepublicBooleancanChange(OrderStatusorderStatus){switch(orderStatus){caseREFUNDED:caseFAIL_REFUNDED:returntrue;default:returnfalse;}}},REFUNDED("退款成功",3),FAIL_REFUNDED("退款失败",4),;privatefinalStringname;privatefinalintstatus;privateOrderStatus(Stringname,intstatus){this.name=name;this.status=status;}//自定义转换方法publicBooleancanChange(OrderStatusorderStatus){returnfalse;}}调用方法:publicclassEnumTest{publicstaticvoidmain(String[]args){BooleanaBoolean=顺序Status.NO_PAY.canChange(OrderStatus.PAY);StringstatusStr=aBoolean?“可以”:“没有Yes";System.out.println("能否完成状态转换:"+statusStr);Booleanflag=OrderStatus.REFUNDED.canChange(OrderStatus.FAIL_REFUNDED);StringflagStr=flag?"Yes":"No";System.out.println("Isitpossibletocompletethestatetransition:"+flagStr);}}返回结果:这样我们使用枚举类来实现订单状态转换的限制,这个例子只是提供一个思路状态转换,具体过程还是需要根据自己系统中的业务具体处理。
