【0】README
0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 自动拆箱(装箱)、printf的参数数量可变 以及 枚举类的详细说明;
0.2) 源代码: https://github.com/pacosonTang/core-java-volume/blob/master/chapter5/chapter5_pack_unpacking_enum.java;
【1】 对象包装器与自动装箱
1.1)包装器定义:所有的基本类型都对应一个类,如int基本类型对应Integer类, 这些类就称为包装器;
1.2)包装器类名字: Integer、Long、Float、Double、Short、Byte、Character、Void、Boolean,前6个类派生于公共超类Number;
1.3)对象包装器类是不可变的, 即一旦构造包装器,就不允许更改包装在其中的值;
1.4)同时,对象包装器类还是 final, 因此不能定义它们的子类;
Warning)由于每个值分别包装在对象中, 所以 ArrayList 的效率远远低于int[] 数组,因此,应该用它构造小型集合,原因是 此时程序员操作的方便性要比执行效率更加重要;
1.5)自动装箱: list.add(3); 等价于 list.add(Integer.valueOf(3)); 这种变换就称为自动装箱;
1.6)自动拆箱:将一个Integer对象 赋给一个 int值时,将会自动拆箱;
int n = list.get(i); 等价于 int n = list.get(i).intValue();
1.7)一种假象: 认为基本类型与他们的对象包装器是一样的, 只是他们的相等性不同;包装器类的 == 运算符检测的是对象是否指向同一个存储区域;
Integer a = 1000;
Integer b = 1000;
if(a == b) ; return false;
1.8)解决假象的方法: 是在两个包装器对象比较时调用 equals方法;
Annotation)自动装箱规范要求 boolean、byte、char<=127,介于 -128~127 间的short和int 被包装到固定的对象中;
1.9)最后强调: 装箱和拆箱是被编译器认可的, 而不是虚拟机;
1.10)使用数值对象包装器 还有一个好处: 可以将某些基本方法放置在 包装器中, 如, 将一个数字字符串转换成数值; 如 int x = Integer.parseInt(s);
【2】参数数量可变的方法
2.1)printf 方法是这样定义的:
public class PrintStream
{public PrintStream printf(String fmt, Object... args) {return format(fmt, args) ;}
}
- 2.1.1)这里的省略号… : 是java程序的一部分, 它表明这个方法可以接收任意数量的对象(除 fmt参数外);
2.2)实际上, printf 方法接收了两个参数, 一个是格式字符串,另一个是 Object[] 数组, 其中存储着所有的参数;换句话说, 对于printf来说, Object… 与 Object[] 完全一样;
2.3)编译器需要对printf的每次调用进行转换, 以便将从参数绑定到数组上,并在必要的时候进行自动装箱:
Syste.out.printf("%d %s", new Object[]{ new Integer(n), "widgets"} );
2.4)用于自定义可变参数的方法(计算若干个数值的方法):
public static double max(double... values)
{double largest = Double.MIN_VALUE;for(double v: values) if(v > largest) largest = v;return largest;
}
可以这样调用:
double m = max(1, 2, 3);编译器将 new double[] { 1, 2, 3} 传递给 max方法;
Annotation) 可以将 一个数组传递给 可变参数方法的最后一个参数:
System.out.printf(%d %s", new Object[]{new Integer(1), "widgets"});
【3】枚举类
3.1)看个荔枝:
public enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE};
实际上, 这个说明定义的类型是一个类, 在此尽量不要构造新对象;
- 3.1.1)因此, 在比较两个枚举类型时,不需要使用 equals, 而直接使用 == 就可以了;
3.2)构造器只是在构造枚举常量的时候被调用:
public enum Size
{SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL");private Size(String abbreviation) {this.abbreviation == abbreviation};public String getAbbreviation() { return abbreviation; }
}
3.3)所有的枚举类型都是 Enum类的子类: 它们继承了这个类的许多方法,包括toString方法, 它可以返回枚举常量名;如, Size.SMALL.toString() 将返回字符串 “SMALL”;
3.4)toString 的逆方法是静态方法valueOf: 如,Size s = Enum.valueOf(Size.class, “SMALL”); 将s 设置为 Size.SMALL;
3.5)每个枚举类型都有一个静态的values方法: 它将返回一个包含全部枚举值的数组;
Size[] values = Size.values();
3.6)ordinal : 该方法返回enum声明中枚举常量的位置, 从0开始计数;
如, Size.MEDIUM.ordinal() 返回 1;
Annotation) Enum类省略了一个类型参数, 例如,实际上, 应该将枚举类型 Size 扩展为Enum ;