java枚举和自动拆箱与装箱
枚举总结篇1
一:枚举类的使用
枚举类,相比于其他的类,枚举类不能被其他类实例化,只能在枚举类里面实例化对象供外部使用。
若枚举类只有一个成员,则可以作为一种单例模式的实现方式。枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰
枚举类使用 private final 修饰的属性应该在构造器中为其赋值,若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的传入参数
二:自定义枚举类
//1.提供类的属性,声明为private final
//2.为私有final属性在构造器里面进行初始化
//创建枚举类的对象,将类的对象声明为public static final
1 package Enum; 2 //枚举类,相比于其他的类,枚举类不能被其他类实例化,只能在枚举类里面实例化对象供外部使用。 3 //若枚举类只有一个成员,则可以作为一种单例模式的实现方式。枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰 4 //枚举类使用 private final 修饰的属性应该在构造器中为其赋值,若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的传入参数 5 public class Enum { 6 public static void main(String[] args) { 7 Season spring = Season.SPRING; 8 System.out.println(spring); 9 spring.show(); 10 System.out.println(spring.getSeasonDesc()); 11 } 12 } 13 class Season{ 14 //1.提供类的属性,声明为private final 15 private final String seasonName; 16 private final String seasonDesc; 17 //2.为私有final属性在构造器里面进行初始化 18 private Season(String seasonDesc,String seasonName){ 19 this.seasonDesc = seasonDesc; 20 this.seasonName = seasonName; 21 } 22 23 public String getSeasonName() { 24 return seasonName; 25 } 26 27 public String getSeasonDesc() { 28 return seasonDesc; 29 } 30 //创建枚举类的对象,将类的对象声明为public static final 31 public static final Season SPRING = new Season("spring","春暖花开");//名字要全部大写 32 public static final Season SUMMER = new Season("summer","夏日炎炎"); 33 public static final Season AUTUMN = new Season("autumn","秋高气爽"); 34 public static final Season WINTER = new Season("winter","白雪皑皑"); 35 36 @Override 37 public String toString() { 38 return "Season{" + 39 "seasonName='" + seasonName + '\'' + 40 ", seasonDesc='" + seasonDesc + '\'' + 41 '}'; 42 } 43 public void show(){ 44 System.out.println("这是一个季节"); 45 } 46 }
三:enum定义的枚举类
1 package Enum; 2 3 public class TT { 4 public static void main(String[] args) { 5 Season1 test1 = Season1.TEST; 6 test1.show(); 7 Season1[] values = Season1.values();//获取类Season1的所有枚举类 8 for (int i = 0; i < values.length; i++) { 9 System.out.println(values[i]); 10 } 11 //2.valueOf(String name):要求传入的形参name是枚举类对象的名字。 12 //否则,报java.lang.IllegalArgumentException异常 13 Season1 name = Season1.valueOf("TEST"); 14 System.out.println(name); 15 } 16 } 17 /* 18 * 一、枚举类 19 * 1.如何自定义枚举类 20 * 2.如何使用enum关键字定义枚举类 21 * >常用的方法:values() valueOf(String name) 22 * >如何让枚举类实现接口:可以让不同的枚举类的对象调用被重写的抽象方法,执行的效果不同。(相当于让每个对象重写抽象方法) 23 */ 24 interface Info{//枚举的对象可以分别去重写方法 25 void show(); 26 } 27 enum Season1 implements Info{//用关键字enum代替class 28 34 35 TEST("ll","23"){//TEST就是对象名,括号就是构造器和初始化的对象 36 public void show(){//重写的接口的方法,这样可以保证每个对象重写的方法是不同的。 37 System.out.println("对象1"); 38 }; 39 },//不同的枚举类用,进行分开 40 TEST1("ll1","231"){ 41 public void show1(){ 42 System.out.println("对象2"); 43 } 44 }; 45 private final String name; 46 private final String age; 47 48 private Season1(String name, String age) { 49 this.age = age; 50 this.name = name; 51 } 52 53 public String getName() { 54 return name; 55 } 56 57 public String getAge() { 58 return age; 59 } 60 61 @Override 62 public String toString() { 63 return "Season1{" + 64 "name='" + name + '\'' + 65 ", age='" + age + '\'' + 66 '}'; 67 } 68 public void show(){ 69 System.out.println("this is a test"); 70 } 71 72 }
枚举总结篇2
- 什么是枚举?
我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
我们称呼枚举类中实例为枚举项!一般一个枚举类的枚举项的个数不应该太多,如果一个枚举类有30个枚举项就太多了! - 定义枚举类型
定义枚举类型需要使用enum关键字,例如:
注意,定义枚举类的关键字是enum,而不是Enum,所有关键字都是小写的!
其中FRONT、BEHIND、LEFT、RIGHT都是枚举项,它们都是本类的实例,本类一共就只有四个实例对象。
在定义枚举项时,多个枚举项之间使用逗号分隔,最后一个枚举项后需要给出分号!但如果枚举类中只有枚举项(没有构造器、方法、实例变量),那么可以省略分号!建议不要省略分号!
不能使用new来创建枚举类的对象,因为枚举类中的实例就是类中的枚举项,所以在类外只能使用类名.枚举项。
- 枚举与switch
枚举类型可以在switch中使用
Direction d = Direction.FRONT; switch(d) { case FRONT: System.out.println("前面");break; case BEHIND:System.out.println("后面");break; case LEFT: System.out.println("左面");break; case RIGHT: System.out.println("右面");break; default:System.out.println("错误的方向"); } Direction d1 = d; System.out.println(d1);
注意,在switch中,不能使用枚举类名称,例如:“case Direction.FRONT:”这是错误的,因为编译器会根据switch中d的类型来判定每个枚举类型,在case中必须直接给出与d相同类型的枚举选项,而不能再有类型。
- 所有枚举类都是Enum的子类
所有枚举类都默认是Enum类的子类,无需我们使用extends来继承。这说明Enum中的方法所有枚举类都拥有。
- int compareTo(E e):比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序,例如FRONT的下标为0,BEHIND下标为1,那么FRONT小于BEHIND;
- boolean equals(Object o):比较两个枚举常量是否相等;
- int hashCode():返回枚举常量的hashCode;
- String name():返回枚举常量的名字;
- int ordinal():返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0;
- String toString():把枚举常量转换成字符串;
- static T valueOf(Class enumType, String name):把字符串转换成枚举常量。
- 枚举类的构造器
枚举类也可以有构造器,构造器默认都是private修饰,而且只能是private。因为枚举类的实例不能让外界来创建!
enum Direction { FRONT, BEHIND, LEFT, RIGHT;//[在枚举常量后面必须添加分号,因为在枚举常量后面还有其他成员时,分号是必须的。枚举常量必须在枚举类中所有成员的上方声明。] Direction()//[枚举类的构造器不可以添加访问修饰符,枚举类的构造器默认是private的。但你自己不能添加private来修饰构造器。] { System.out.println("hello"); } }
其实创建枚举项就等同于调用本类的无参构造器,所以FRONT、BEHIND、LEFT、RIGHT四个枚举项等同于调用了四次无参构造器,所以你会看到四个hello输出。
- 枚举类可以有成员
其实枚举类和正常的类一样,可以有实例变量,实例方法,静态方法等等,只不过它的实例个数是有限的,不能再创建实例而已。
enum Direction { FRONT("front"), BEHIND("behind"), LEFT("left"), RIGHT("right"); private String name; Direction(String name) { this.name = name; } public String getName() { return name; } } Direction d = Direction.FRONT; System.out.println(d.getName());
因为Direction类只有唯一的构造器,并且是有参的构造器,所以在创建枚举项时,必须为构造器赋值:FRONT(“front”),其中”front”就是传递给构造器的参数。你不要鄙视这种语法,你应该做的是接受这种语法!
Direction类中还有一个实例域:String name,我们在构造器中为其赋值,而且本类还提供了getName()这个实例方法,它会返回name的值。
- 枚举类中还可以有抽象方法
还可以在枚举类中给出抽象方法,然后在创建每个枚举项时使用“特殊”的语法来重复抽象方法。所谓“特殊”语法就是匿名内部类!也就是说每个枚举项都是一个匿名类的子类对象!
通常fun()方法应该定义为抽象的方法,因为每个枚举常量都会去重写它。
你无法把Direction声明为抽象类,但需要声明fun()方法为抽象方法。
enum Direction { FRONT() { public void fun() { System.out.println("FROND:重写了fun()方法"); } }, BEHIND() { public void fun() { System.out.println("BEHIND:重写了fun()方法"); } }, LEFT() { public void fun() { System.out.println("LEFT:重写了fun()方法"); } }, RIGHT() { public void fun() { System.out.println("RIGHT:重写了fun()方法"); } }; public abstract void fun()[只需要把fun()方法修改为抽象方法,但不可以把Direction类声明为抽象类。]; }
将一个类的构造函数私有化,可以使得该类不被实例化,和不能被继承。要创建这个类的实例,唯一的办法是提供一个公共静态方法在类内部实例化。这种方式被称为单例模式
- 每个枚举类都有两个特殊方法
每个枚举类都有两个不用声明就可以调用的static方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方,下面是Direction类的特殊方法。
- static Direction[] values():返回本类所有枚举常量;
- static Direction valueOf(String name):通过枚举常量的名字返回Direction常量,注意,这个方法与Enum类中的valueOf()方法的参数个数不同。
static和final的说明
* 在java中用final修饰符修饰的变量表示不可以被二次赋值,且系统不会给其赋默认值。 * 如果单纯只是final变量,可以在定义的时候就赋默认值,也可以在构造方法中赋默认值。 * static属性是属于类的,所以在使用构造器之前就被系统赋默认值。 * 那么static final就要求在定义的时候就要显示初始化才行。
java 自动装箱与拆箱
java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的(在这种情况下包装成为装箱,解包装称为拆箱);
其实按照我自己的理解自动装箱就可以简单的理解为将基本数据类型封装为对象类型,来符合java的面向对象;例如用int来举例:
//声明一个Integer对象 Integer num = 10; //以上的声明就是用到了自动的装箱:解析为 Integer num = new Integer(10);
以上就是一个很好的体现,因为10是属于基本数据类型的,原则上它是不能直接赋值给一个对象Integer的,但jdk1.5后你就可以进行这样的声明,这就是自动装箱的魅力
自动将基本数据类型转化为对应的封装类型。成为一个对象以后就可以调用对象所声明的所有的方法
自动拆箱:故名思议就是将对象重新转化为基本数据类型:
//装箱 Integer num = 10; //拆箱 int num1 = num;
自动拆箱有个很典型的用法就是在进行运算的时候:因为对象时不恩直接进行运算的,而是要转化为基本数据类型后才能进行加减乘除
Integer num = 10; //进行计算时隐含的有自动拆箱 System.out.print(num--);
哈哈 应该感觉很简单吧,下面我再来讲点稍微难点的,是稍微
看下面一个例子,在看下面一个例子时如果对于 == 与 equal的区别不清楚的,可以先看http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452156.html
//在-128~127 之外的数 Integer num1 = 297; Integer num2 = 297; System.out.println("num1==num2: "+(num1==num2)); // 在-128~127 之内的数 Integer num3 = 97; Integer num4 = 97; System.out.println("num3==num4: "+(num3==num4));
打印的结果是:num1==num2: false num3==num4: true
很奇怪吧:这就归结于java对于Integer与int的自动装箱与拆箱的设计,是一种模式:叫享元模式(flyweight)
为了加大对简单数字的重利用,java定义:在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象
而如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象;明白了吧
以上的现象是由于使用了自动装箱所引起的,如果你没有使用自动装箱,而是跟一般类一样,用new来进行实例化,就会每次new就都一个新的对象;
这个的自动装箱拆箱不仅在基本数据类型中有应用,在String类中也有应用,比如我们经常声明一个String对象时:
String str = "sl"; //代替下面的声明方式 String str = new String("sl");
@Test public void test(){ String str1 = "aa";//相当于自动装箱 String str2 = "aa"; System.out.println(str1==str2);//true String s = new String("123"); String s1 = new String("123"); System.out.println(s==s1);//false }