------- android培训、java培训、期待与您交流! ----------
Jdk1.5新增了一些新的语言特性来简化开发,这些特性包括泛型,增强for循环,格式化打印,自动拆箱/装箱,枚举,可变参数,静态导入。使用这些特性有助于我们编写更加清晰,简洁,健壮性更强的代码。下面我们整体介绍一个这些新特性。
泛型(Generic Type)
C++通过模板技术可以指定集合的元素类型,而Java在1.5之前一直没有相对应的功能。一个集合可以放任何类型的对象,相应地从集合里面拿对象的时候我们也不得不对他们进行强制得类型转换。Jdk1.5引入了泛型,它允许指定集合里元素的类型,这样你可以得到强类型在编译时刻进行类型检查的好处。
List<String>list =newArrayList();
c.add(new Integer(25));
编译器会给出一个错误:
The method add(String) in the type List<String> is not applicable for the arguments (Integer)
增强for循环(For-Each)
在jdk1.4以及之前的版本中,数组要使用下标进行遍历,集合类型对象要使用迭代器Iterator进行遍历。jdk1.5增加了增强for循环的概念,只需按照for(类型 类型名 : 集合名或数组名){}方式即可完成对数组和实现了Iterable接口的集合类对象进行简洁的遍历操作,如下所示:
int[] nums = new int{};
int[] nums = new int[]{1,2,3,4,5};
for(int num:nums){
System.out.println(num);
}
List<String> list = new ArrayList<String>();
for(String s:list){
System.out.println(s);
}
上述代码不但简洁易懂,而且避免了强制类型转换。
自动装箱/拆箱(Autoboxing/unboxing)
自动装箱/拆箱大大方便了基本类型数据和它们包装类地使用。自动装箱是指基本类型自动转为包装类;自动拆箱是指包装类自动转为基本类型。在JDK1.5之前,集合和对象数组中不能直接存放基本数据类型,而是需要直观的将其改成包装类再存储,而自动装箱特性很好简化了这个过程。
Integer num1 = 3;//自动装箱,相当于Integer num1 = new Integer(3);
System.out.println(num1+12);//自动拆箱,相当于System.out.println(num.intValue()+12);
枚举(Enums)
枚举就是要让某个类型的变量的取值只能为若干固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。 我们首先通过模拟一个 enum类来了解其内部运行机制。
public abstract class Color {
private Color(){}
public static final Color RED = new Color(){
public Color nextDay() {
return BLUE;
}
};
public static final Color BLUE = new Color(){
public Color nextDay() {
return GREEN;
}
};
public static final Color GREEN = new Color(){
public Color nextDay() {
return RED;
}
};
public abstract Color nextDay();
@Override
public String toString(){
if(this==RED) return "RED";
else if(this==BLUE) return "BLUE";
else return "GREEN";
}
}
这样我们就得到了一个抽象类
Color
,其使用方法类似于
enum
类型的变量。接下来我们定义一个
enum
类,如下:
public enum TrafficLamp{
//带了抽象方法的枚举类,元素后直接跟{}定义匿名类,调用父类有参的构造方法
RED(30) {
@Override
public TrafficLamp nextLamp() {
return GREEN;
}
},
GREEN(45) {
@Override
public TrafficLamp nextLamp() {
return YELLOW;
}
},
YELLOW(5) {
@Override
public TrafficLamp nextLamp() {
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time){this.time = time;}
}
并作如下测试:
TrafficLamp tl = TrafficLamp.RED;
System.out.println(tl);
System.out.println(tl.name());
System.out.println(tl.getClass().getName());
System.out.println(TrafficLamp.valueOf("GREEN"));
System.out.println(TrafficLamp.values().length);
运行结果为:
RED
RED
com.hunnu.day1.TrafficLamp$1
GREEN
3
结合我们模拟enum的类Color和jdk文档我们知道:
枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
枚举元素必须位于枚举体中的最开始部分,美居元素列表后要有分号与其他成员分隔开。把枚举中的成员方法或变量等放在枚举元素前面,编译会报错。
对于带构造方法的枚举:构造方法必须定义成私有的;如果有多个构造方法,用法类似于直接传递参数的方式进行调用;枚举元素RED和RED()的效果一样,都是调用默认的构造方法。
可变参数(Varargs)
可变参数使程序员可以声明一个接受可变数目参数的方法。注意,可变参数必须是函数声明中的最后一个参数。假设我们要写一个简单的方法打印一些对象,
util.write(obj1);
util.write(obj1,obj2);
util.write(obj1,obj2,obj3);
…
在JDK1.5之前,我们可以用
多个方法
重载来实现,
这样会显得很臃肿,可读性不强,而是用可变参数的重载方式,只需要一个函数即可:
publicvoidwrite(Object...objs){
for(Objectobj:objs)
System.out.println(obj);
}
可变参数有以下特点:
可变参数只能出现在参数列表的最后;
...位于变量类型和变量名之间,前后有无空格都可以;
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组形式访问可变参数。
实际上,在引入可变参数之前,反射机制中多参数的传递往往是通过数组实现的如jdk1.4之前利用Constructor对象获得实例constructor.newInstance(Object[] initargs),而现在的方式是newInstance(Object... initargs),这样给开发者提供了更大的灵活性
静态导入(StaticImports)
要使用用静态成员(方法和变量)我们必须给出提供这个方法的类。使用静态导入可以使被导入类的所有静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给出他们的类名。
Import static ava.lang.Math.*; //或者import static java.lang.Math.sin;import static java.lang.Math.PI;
double r = sin(PI * 2);//无需再写r = Math.sin(Math.PI);
不过,过度使用这个特性也会一定程度上降低代码地可读性。
格式化打印(formatted print)
C语言中printf()风格的格式化输出。
这里只举一个thinking in java的一个例子:
public class SimpleFormat {
public static void main(String[] args) {
int x = 5;
double y = 5.332542;
//The old way
System.out.println("Row 1: ["+x+" "+y+"]");
//The new way
System.out.format("Row 1: [%d %f]\n", x,y);
//or
System.out.printf("Row 1: [%d %f]\n", x, y);
}
}
运行结果:
Row 1: [5 5.332542]
Row 1: [5 5.332542]
Row 1: [5 5.332542]
可以看到,format和printf是等价的,他们只需要一个简单的格式化字符串,加上一串参数即可,每个参数对应一个格式修饰符