jdk1.5之后的一些新特性,特此总结一下,在java中,自从jdk1.5之后便出现了一些新特性
包括:泛型(Generic) ,注解,For-Each,自动拆箱和装箱,静态导入,格式化打印,枚举,可变参数...
1.泛型(Generic)和注解
泛型:
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
编辑本段规则和限制
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");
注解:
注解是程序向编译器传达某种编译信息的方式。比如对一些过时的方法,编译器在编译的时候会提醒程序员:此方法不推荐使用。但是程序员觉得看到这个提示很不爽,于是说:“哥玩了几十年的程序,这个都不知道吗?你不用给我提示了,我懂滴。”于是程序员在程序中嵌入一句
@SuppressWarnings("deprecated");这行代码表示关闭方法过时提示。于是编译器就乖乖的不提示了。这就是注解!
注解的语法,除了@符号的使用以外,它基本上与java的固有语法一致,java内置了三种
注解,定义在java.lang包中。
@Override 表示当前方法是覆盖父类的方法。使用这个注解,是告诉编译器,这里必须是覆盖父类的方法。如果你发现不是覆盖父类方法的,请打断它的腿!
@Deprecated 表示当前元素是不赞成使用的。若在程序中使用了这个注解,编译会提示这个方法过时,但可以运行。
@SuppressWarnings 叫压缩警告,表示关掉编译器的某些警告。告诉编译器,你少罗嗦,照编译就可以了!
2.增强for循环(for-each)
- 用Iterator实现如下:
- import java.util.ArrayList;
- import java.util.Collection;
- public class GenericTest {
- public static void main(String[] args) {
- Collection c = new ArrayList();
- c.add("aa");
- c.add("bb");
- for(Iterator i=c.iterator(); i.hasNext();){
- String s= (String)i.next();
- System.out.println(s);
- }
- }
- }
- 运行结果:
- aa
- bb
用for-each更简单:
- import java.util.ArrayList;
- import java.util.Collection;
- public class GenericTest {
- public static void main(String[] args) {
- Collection<String> c = new ArrayList<String>();
- c.add("aa");
- c.add("bb");
- for(String s:c){
- System.out.println(s);
- }
- }
- }
- 运行结果:
- aa
- bb
3.自动装箱拆箱(Autoboxing/unboxing)
例3-1代码
自动装箱拆箱大大方便了基本类型数据和它们封装类地使用。
自动装箱:基本类型自动转为封装类.(int >> Integer)
自动拆箱:封装类自动转为基本类型.(Integer >> int)
在JDK1.5之前,我们总是对集合不能存放基本类型而耿耿于怀,
现在自动转换机制解决了我 们的问题。
int a = 3;
Collection c = new ArrayList();
c.add(a);//自动转换(装箱)成Integer.
Integer b = new Integer(2);
c.add(b + 2);
这里Integer先自动转换(拆箱)为int进行加法运算,然后int再次转换(装箱)为Integer.
- public class T {
- public static void main(String[] args) {
- Integer i1 = 128;
- Integer i2 = 128;
- int i3 = 128;
- int i4 = 128;
- Integer i5 = 127;
- Integer i6 = 127;
- Long long1 = 128L;
- Long long2 = 128L;
- long long3 = 128L;
- long long4 = 128L;
- long long5 = -128L;
- long long6 = -128L;
- //-128 ~ 127之间数值装箱时会共享内存副本, 超过这个范围,则不会共享引用,即对象地址将不同
- System.out.println(i1 == i2); //实质是比较两个不同引用 false
- System.out.println(i5 == i6); //实质是比较两个相同(共享)引用true
- System.out.println(i1 == i3); //先将i1拆箱,然后比较基本类型 true
- System.out.println(i1.equals(i4)); //先将i4装箱,然后比较基本类型 true
- System.out.println(long1 == long2);//两个引用不同 false
- System.out.println(long5 == long6);//共用副本 true
- System.out.println(long1 == long3);//long1先拆箱, 在比较 true
- System.out.println(long2.equals(long4));//long4先装箱, 再equals, true
- }
- }
-
4.静态导入(static import)
要使用用静态成员(方法和变量)我们必须给出提供这个方法的类。使用静态导入可以使被导入类的所有静态变量和静态方法在当前类直接可调用,使用这些静态成员无需再给出他们的类名。
- //静态导入Math的所有方法
- import static java.lang.Math.*;
- public class StaticImportTest {
- public static void main(String[] args){
- //类中生成随机数数可以直接使用静态引入的random方法了,而不用Math.random()这样调用了
- System.out.println(random());
- 又:
- System.out.println(max(3, 6));//无需写Math.max();
- r = sin(PI * 2); //无需再写r = Math.sin(Math.PI);
- }
- }
5.格式化打印(formatted print)
C语言中printf()风格的格式化输出。
这里只举一个thinking in java的一个例子:
例5-1代码
- 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是等价的,他们只需要一个简单的格式化字符串,加上一串参数即可,每个参数对应一个格式修饰符
6.枚举(Enums)
JDK1.5加入了一个全新类型的“类”-枚举类型。为此JDK1.5引入了一个新关键字enmu. 我们可以这样来定义一个枚举类型。
当每一类型可取值范围是有限的时候,可以使用枚举,例如每个学生登记只能用ABCD表示,如果直接用E的话,那么编译不会出错,但是却不符合输入要求,而使用枚举增加程序的易读性和健壮性?
Java代码
- public class GradeTest {
- public static void main(String[] args) {
- Student stu = new Student();
- stu.setName("wasw100");
- stu.setGrade(Grade.A);
- //输出学生信息
- System.out.println(stu);
- }
- }
- /**
- * 枚举:Grader 学生考试等级
- * @author wasw100
- */
- enum Grade{
- A,B,C,D
- }
- class Student {
- private String name;
- private Grade grade;
- //重写toString()方法
- public String toString(){
- return "name:+"+name+"\ngrader:"+grade;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Grade getGrade() {
- return grade;
- }
- public void setGrade(Grade grade) {
- this.grade = grade;
- }
- }
-
7.可变长参数(varargs)
可变参数使程序员可以声明一个接受可变数目参数的方法。
注意,可变参数必须是函数声明中的最后一个参数。
假设我们要写一个简单的方法打印一些对象,在jdk1.5以前我们需要重载多个方法
util.write(obj1);
util.write(obj1,obj2);
util.write(obj1,obj2,obj3);
…
在JDK1.5之前,我们可以用重载来实现,但是这样就需要写很多的重载函数,显得不是很有效。如果使用可变参数的话我们只需要一个函数就行了
public void write(Object... objs) {
for (Object obj: objs)
System.out.println(obj);
}
下面是一个唐僧给悟空讲佛经的例子
Java代码
- public class VarargsTest {
- public void speak(String name, Object... arguments) {
- System.out.print(name+": ");
- for (Object object : arguments) {
- System.out.print(object);
- }
- System.out.println();
- }
- public static void main(String[] args) {
- VarargsTest vt = new VarargsTest();
- vt.speak("悟空", "人和妖精都是妈生的,");
- vt.speak("悟空", "不同的人是人他妈生的,", "妖是妖他妈生的,");
- }
- }
- 运行结果:
- 悟空: 人和妖精都是妈生的,
- 悟空: 不同的是,人是人他妈生的,妖是妖他妈生的,