-------android培训、java培训、期待与您交流! ----------
对象包装器与自动打包:
所有的基本类型都有一个与之对应的类,通常这些类称为包装器(wrapper)。这些包装器拥有很鲜明的名字:Integer、Long、Float、Double、Short、Byte、Character、Void和Boolean(前6个类派生于公共的超类Number)。对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装器其中的值。同时,对象包装器类还是final,因此不能定义它们的子类。
假设想定义一个整型数组列表,而尖括号中的类型参数不允许是基本类型,也就是说,不允许写成ArrayList<int>,这里就要用到Integer对象包装器类,我们可以声明一个Integer对象的数组列表:
ArrayList<Integer> list = newArrayList<Integer>();
PS:由于每个值分别包装在对象中,所以ArrayList<Integer>的效率远低于int[]数组。因此,应该用它构建小型集合,其原因是此时程序操作的方便性要比执行效率更加重要。
Java SE 5.0的另一个改进之处是更加便于添加或获得数组元素,下面这个调用:
list.add(3);
将自动的变换成:
list.add(new Integer(3));
这种变换被称为自动打包(autoboxing)。
相反的,当将一个Integer对象赋值给一个int值时,将会自动拆包。也就是说,编译器将下列语句:
int n = list.get(i);
翻译成:
int n = list.get(i).intValue();
甚至在算术表达式中也能够自动的打包和拆包。例如,可以将自增操作符应用于一个包装器引用:
Integet n = 3;
n++;
编译器将自动的插入一条拆开对象包的指令,然后进行自增计算,最后再将结果打入对象包内。
在两个包装器对象比较时一般调用equals方法。==运算符检测的是对象是否指向同一个存储区域,通常不会成立。
最后强调一下,打包和拆包是编译器认可的,而不是虚拟机。编译器在生成类的字节码时,插入必要的方法调用,虚拟机只是执行这些字节码。
使用数值对象包装器还有另外一个好处。Java类的设计者发现,可以将某些基本方法放置在一个包装器中,例如,将一个数字字符串转换成数值。
要想将字符串转换成整型,可以使用下面的语句:
int x = Integer.parseInt(s);
这里与Integer对象没有任何关系,parseInt是一个静态方法。但Integer类是放置这个方法的一个好地方。
参数数量可变的方法
从Java SE 5.0开始,提供了可以用可变的参数数量调用的方法(有时称为“可变参”方法)。
前面已经看到过这样的方法:printf。例如,下面的方法调用:
System.out.printf(“%d”,n);
System.out.printf(“%d%s”,n,”widgets”);
在上面两条语句中,尽管一个调用包含两个参数,另一个调用包含三个参数,但它们调用的都是同一个方法。printf方法是这样定义的:
public class PrintStream
{
public PrintStream printf(Stringfmt,Object…args)
{
return format(fmt,args);
}
}
这里的省略号…是Java代码的一部分,它表明这个方法可以接收任意数量的对象(除fmt参数之外)。
实际上,printf方法接收两个参数,一个是格式字符串,另一个是Object[]数组,其中保存这所有的参数(如果调用者提供的是整型数组或者其他基本类型的值,自动打包功能键把它们转换成对象)。
现在将扫描fmt字符串,并将第i个格式说明符与args[i]的值匹配起来。
编译器需要对printf的每次调用进行转换,以便将参数绑定到数组上,并在必要的时候进行自动打包:
System.out.printf(“%d %s”, newObject[] { new Integer(n) , widgets”});
用户自己也可以定义可变参数的方法,并将参数指定为任意类型,甚至是基本类型。下面是一个简单的示例:其功能为计算若干个数值的最大值。
public static double max(double…values)
{
doublelargest = Double.MIN_VALUE;
for(doublev : values) if(v > largest) largest = v;
returnlargest;
}
可以像下面这样调用这个方法:
double m = max(3.1,40.5,-5);
编译器将new double[]{3.1,40.5,-5}传递给max方法。
PS:允许将一个数组传递给可变参数方法的最后一个参数。
枚举类
例:
public enumSize{SMALL,MEDIUM,LARGE,EXTRA_LARGE};
实际上,这个声明定义的类型是一个类,它刚好有4个实例,在此尽量不要构造新对象。
因此,在比较两个枚举类型的值时,永远不需要equals,而直接使用“==”就可以了。
如果需要的话,可以在枚举类型中添加一些构造器、方法和域。当然,构造器只是在构造枚举常量的时候被调用。
enumSize
{
SMALL(“S”),MEDIUM(“M”),LARGE(“L”),EXTRA_LARGE(“XL”);
private Size(String abbreviation)
{
this.abbreviation =abbreviation;
}
public String getAbbreviation()
{
return this.abbreviation;
}
private String abbreviation;
}
所有的枚举类型都是Enum的子类。它们继承了这个类的许多方法。其中最有用的一个是toString,这个方法能够返回枚举常量名。例如:Size.SMALL.toString()将返回字符串“SMALL”。
toString()的逆方法是静态方法valueOf。例:
Size s = (Size)Enum.valueOf(Size.class , “SMALL”);
将s设置为Size.SMALL。
每一个枚举类型都有一个静态的values方法,它将返回全部的枚举值的数组:
Size[] values = Size.values();
返回包含元素Size.SMALL、Size.MEDIUM、Size.LARGE和Size.EXTRA_LARGE的数组。
ordinal方法返回enum声明中枚举量的位置,位置从0开始计数。例如:Size.MEDIUM.ordinal()返回1.