JDK1.5以后提供了新的导入语句:静态导入语句。
有时候你需要频繁访问一个static final的字段(常量),或者静态方法,这些静态成员都来自同一个类。给这个类的这些成员一遍遍加前缀会使代码很混乱。静态导入语句给你一种导入常量和静态方法的方式,这种方式不需要给这些常量和静态方法加类名前缀。
例如java.lang.Math类定义了PI常量和许多静态方法,包括计算最大值,最小值,平方根,正弦值,余弦值的方法。通常为了用这些来自其他类的对象,你需要加类名前缀,如下所示:
double r =Math.cos(Math.PI*theta)你可以用静态导入语句导入java.lang.Math的静态成员,这样你就不用加类名前缀Math。
可以用下面的方式单独导入一个静态成员:
import static java.lang.Math.PI;也可以用下面的方式导入所有静态成员:
import static java.lang.Math.*;
一旦这些静态成员被导入,使用他们就不需要加类名前缀。例如最前面的代码片可以改为:
double r = cos(PI * theta);注意:请不要过度使用静态导入语句,因为过度使用静态导入语句会导致代码难以阅读和维护,因为代码的读者不知道某一个静态对象到底被定义在哪个类中。合适的使用静态导入语句,可以通过取出类名前缀的方式使代码更具可读性。
Java可变参数(varargs)是JDK1.5提供的新特性,它的作用是使一个方法可以接受任意数量的参数。
例如:
class VarargsDemo{ public static void main(String[] args) { printMany();//也可以不传入参数 printMany(1); printMany(2,3); printMany(4,5,6); } public static void printMany(int... varargs){ for (int i=0;i<varargs.length;i++ ) { System.out.print(varargs[i]+" "); } System.out.println(); } }
使用可变参数的方法是在要使用的方法的相应参数的数据类型后边加三个点。可变参数在方法内部的使用像数组一样。
它相对于数组参数的好处是:它可以使方法接受任意数量的实际参数,而数组参数只能使方法接受一个数组类型的参数。在同样接受一系列值得时候,可变参数的方法可以直接接收,而数组参数的方法则要通过封装了一系列值得数组来接收。另外,可变参数的方法也可以接收数组参数。
注意:数据类型加...的形式只能用在方法参数列表上,不能用于其他地方。
增强的for语句也叫foreach语句(在MyEclipse里输入fore再执行自动补全功能会自动补全为增强的for语句),主要用于对集合和数组进行迭代,它可以使你的循环语句更简洁,更易于阅读。
例子如下:
class EnhancedForDemo{ public static void main(String[] args) { int[] numbers={1,2,3,4,5,6,7,8,9,10}; for (int item : numbers) { System.out.print(item+" "); } } }
1 2 3 4 5 6 7 8 9 10
程序中的item 表示每轮循环,当前遍历到的numbers的元素的值。
增强的for语句只能用于遍历访问数组和集合,但是不能改变数组和集合的值。
能用增强for语句的地方,最好用它代替普通for循环,比如遍历枚举的时候,用foreach语句就比较方法
自动装箱(Autoboxing)是Java编译器在原生数据类型和对应的封装类之间做的一种自动转换。比如把int转为Integer,double转为Double等等。如果这种转换过程倒过来,就叫拆箱(Unboxing)。
这里是一个最简单的装箱例子:
Integer i=100;
这里把一个int型的常量100直接赋给了Integer型的变量i,在JDK1.5之前这样写会报错,但是1.5之后,这样写就没问题,因为系统有了自动装箱功能,原理其实就是调用了Integer类的ValueOf方法,这个ValueOf方法的源码如下:
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }由此可见-128到127之间的int值在第一次自动装箱时会把值存进缓存中,第二次直接取缓存中的值,这也就是下面的程序结果出现的原理:
class Boxing{ public static void main(String[] args) { Integer i1=10; Integer i2=10; System.out.println(i1==i2);//true Integer i3=127; Integer i4=127; System.out.println(i3==i4);//true Integer i5=128; Integer i6=128; System.out.println(i5==i6);//false } }而JDK之所以要将1个字节能存下的整形值保存到缓存中,是因为这个范围的整形值比较常用, 用缓存可以提高效率和节省内存空间,这就叫享元设计模式。关于享元设计模式,请看这里。
最简单的拆箱例子如下:
Integer i1=10; int i2=i1;这里的拆箱就是将Integer类型自动转换为int型。
枚举是JDK1.5提供的新特性。
枚举的声明形式如下:
public enum Week{ SUN,MON,TUE,WED,THI,FRI,SAT; }其中enum是枚举的关键词,这段代码定义了一个名为Week的枚举,其中的成员有星期一到星期日。
public abstract class Week { public final static Week SUN=new Week(){ public String toString() { return "SUN"; }; }; public final static Week MON=new Week(){ public String toString() { return "MON"; }; }; public final static Week TUE=new Week(){ public String toString() { return "TUE"; }; }; public final static Week WED=new Week(){ public String toString() { return "WED"; }; }; public final static Week THI=new Week(){ public String toString() { return "THI"; }; }; public final static Week FRI=new Week(){ public String toString() { return "FRI"; }; }; public final static Week SAT=new Week(){ public String toString() { return "SAT"; }; }; public abstract String toString(); }
这样,要想使用Week类中的常量对象,就需要像下面那么做:
public static void main(String[] args) { Week week1=Week.FRI; System.out.println(week1);//FRI System.out.println(Week.MON);//MON }
public static void main(String[] args) { UserType type=UserType.NormalUser; switch (type) { case NormalUser: System.out.println("一般用户"); break; case Personnel: System.out.println("人员用户"); break; case SeniorUser: System.out.println("高级用户"); break; case VirtualUser: System.out.println("虚拟用户"); break; default: break; } } public enum UserType{ Personnel,NormalUser,SeniorUser,VirtualUser; }上面的代码来自一个常见的场景,各种用户类型在数据库中可能用int型数字表示,如果代码里这么表示,则很快会忘记哪个数字对应哪个数字类型,但是用了枚举以后就不会这样,名字中就包含含义,而且,当不知道有什么类型,可以直接‘点’出来。
public static void main(String[] args) { for (Direction direction : Direction.values()) { System.out.println(direction.getNumber()); } } public enum Direction{ east(1),west(2),north(3),south(4); private int number; private Direction(int number) { this.number=number; } public int getNumber(){ return this.number; } }
public static void main(String[] args) { System.out.println(TrafficLamp.GREEN.getNext()); System.out.println(TrafficLamp.YELLOW.getNext()); System.out.println(TrafficLamp.RED.getNext()); } /** * 交通灯枚举 * @author programBoy */ public enum TrafficLamp{ GREEN{ public TrafficLamp getNext() { return YELLOW; } }, RED{ public TrafficLamp getNext() { return GREEN; } }, YELLOW{ public TrafficLamp getNext() { return RED; } }; public abstract TrafficLamp getNext(); }上面的代码定义了一个交通灯枚举,这个枚举里有三个值GREEN、RED、YELLOW,每个值后边加一个大括号,表示定义了一个匿名内部类,这个匿名内部类是TrafficLamp的子类(Java枚举底层用类实现),而TrafficLamp枚举中定义了一个抽象方法getNext(),所以每个子类都要实现这个方法。之后在使用的时候就可以从枚举值调用这个方法了。
如果有知识点不明确,查找顺序:
Java SE Tutorials 是JDK1.6的英文chm可搜索版本,比JDK1.7的版本要好,因为JDK1.7的版本去掉了关于java.io包的内容
JDK API Reference 是JDK 1.6的简体中文chm可搜索版本
Java Language Specification 是JDK1.5的英文chm可搜索版本