JDK5.0新特性

一、概述
    1.静态导入,Static Import
    2.自动装箱/拆箱,Autoboxing/Unboxing
    3.可变参数,Varargs
    4.增强for循环(for-each),Enhanced for Loop
    5.枚举,Typesafe Enums
    6.泛型,Generics
    7.注解,Annotatioins
二、详细解释
    1.静态导入
        语法:import static 包名.类名.静态属性|静态方法|*
        示例:import static java.lang.Math.max;(这是导入静态方法,此时可以直接使用max(..))
            import static java.lang.System.out;(这是导入静态属性,此时输出可以这么写out.println("helloWorld"))
            import static java.lang.Math.*;(这是导入指定类全部静态属性和方法)
    2.自动装箱/拆箱
        * 自动装箱:把一个基本数据类型直接赋给对应的包装类变量,或者赋给Object变量.
        * 自动拆箱:把包装类对象直接赋给一个对应的基本类型变量.
        (1)jdk1.5之前的基本类型与包装类型转换
            private static void demo(){
                int i = 0;
                Integer j = new Integer(i);
                int m = j.intValue();
            }    
        (2)jdk1.5时,基本类型与包装类型之间的转换
            private static void demo(){
                int i = 0;
                Integer j = i;
                int m = j;
            }
    3.可变参数
        (1)可变参数,即java允许为方法定义长度可变的参数.
            语法:public void foo(int...args){..}
            注意:
                * 可变参数可以当作数组使用.
                * 仅传递对象数组时,数组将被打散.
                * 基本类型数组将被当作一个对象看待.建议在使用可变参数时,尽量不用基本类型,直接使用其包装类型.
                * 可变参数只能处于参数列表的最后(只能有一个可变参数)
                * 可变长参数是Object[]数组.

        (2)示例(测试JDK中具有可变参数的类Arrays.asList()方法)

public static void main(String[] args) {
	List list = Arrays.asList(1,2,3,4,5);//传递多个参数
	
	String[] arrStrs = {"a","bb","ccc"};
	list = Arrays.asList(arrStrs);//传递对象数组
	
	list = Arrays.asList();//无参
	System.out.println(list);//输出为空即:[]
	
	int[] ints = {1,2,3,4,5};//基本类型数组,注意区别对象数组
	list = Arrays.asList(ints);
	System.out.println(list);// 输出为对象的字符串,例如:[[I@459189e1]
}

    4.增强for循环
        (1) * 引入增强for循环的原因:抛弃Iterator
            * foreach语句的使用范围
                    遍历数组
                    遍历实现Iterator接口的集合类.
            * 语法格式;
                    for(变量类型    变量 : 需迭代的数组或集合){}
            * 注意:
                增强for循环不能在遍历时删除和修改数据,因为它隐藏了Iterator.
        (2)简单举例

private static void demo(){
	Person[] arrPers = new Person[3];
	person[0] = new Person("joey","30");
	person[1] = new Person("chanle","31");
	person[2] = new Person("ross","32");
	for(Person p : arrPers){
		System.out.println(p.getName + ":" + p.getAge());
	}
}

    5.枚举
        (1)枚举概述
            * 枚举其实就是一种类型,和int,char相近,就是定义变量时用来限制输入的,而只能赋enum里规定的值.
            * 例如下面的Color枚举类,其枚举值(RED,BLANK..)都是Color类型的类静态常量,这些枚举值都是public static final的,
                即平常写的常量,所以最好全部大写.
            * 枚举中的构造器只能私有private,绝对不允许有public构造器,这样可以保证外部代码无法新构造枚举类的实例.
            * 当枚举值只有一个时,可以理解为单例类.
        (2)为什么需要枚举
            *      如果一个类只能拥有一个实例对象,则可以把它设计成单例类.
                但是一个类,如何限制只可以实例化俩个对象呢?
            * 一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值(例如性别),此类问题在jdk5以前采用自定义带有枚举功能
                的类解决,java5以后可以直接使用枚举予以解决.
        (3)枚举常见应用
            * 常量

public enum Color {
	RED,GREEN,BLANK,YELLOW
}

            * switch
                JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强.

	enum Signal {  
	    GREEN, YELLOW, RED  
	}  
	public class TrafficLight {  
	    Signal color = Signal.RED;  
	    public void change() {  
	        switch (color) {  
	        case RED:  
	            color = Signal.GREEN;  
	            break;  
	        case YELLOW:  
	            color = Signal.RED;  
	            break;  
	        case GREEN:  
	            color = Signal.YELLOW;  
	            break;  
	        }  
	    }  
	}

            * 向枚举中添加新方法

//如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例
	public enum Color {  
	    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); //先写实例,且最后要有分号. 
	    // 成员变量  
	    private String name;  
	    private int index;  
	    // 构造方法  
	    private Color(String name, int index) {  
	        this.name = name;  
	        this.index = index;  
	    }  
	    // 普通方法  
	    public static String getName(int index) {  
	        for (Color c : Color.values()) {  
	            if (c.getIndex() == index) {  
	                return c.name;  
	            }  
	        }  
	        return null;  
	    }  
	    // get set 方法  
	    public String getName() {  
	        return name;  
	    }  
	    public void setName(String name) {  
	        this.name = name;  
	    }  
	    public int getIndex() {  
	        return index;  
	    }  
	    public void setIndex(int index) {  
	        this.index = index;  
	    }  
	} 

            * 覆盖枚举的方法
                toString()方法覆盖的例子

public enum Color {  
	    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
	    // 成员变量  
	    private String name;  
	    private int index;  
	    // 构造方法  
	    private Color(String name, int index) {  
	        this.name = name;  
	        this.index = index;  
	    }  
	    //覆盖方法  
	    @Override  
	    public String toString() {  
	        return this.index+"_"+this.name;  
	    }  
	} 

            * 实现接口
                所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类

    public interface Behaviour {  
        void print();  
        String getInfo();  
    }  
    public enum Color implements Behaviour{  
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
        // 成员变量  
        private String name;  
        private int index;  
        // 构造方法  
        private Color(String name, int index) {  
            this.name = name;  
            this.index = index;  
        }  
    	//接口方法  
        @Override  
        public String getInfo() {  
            return this.name;  
        }  
        //接口方法  
        @Override  
        public void print() {  
            System.out.println(this.index+":"+this.name);  
        }  
    }  

            * 使用接口组织枚举

public interface Food {  
    enum Coffee implements Food{  
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    }  
    enum Dessert implements Food{  
        FRUIT, CAKE, GELATO  
    }  
} 

    6.泛型
        (1)
            * 泛型是对集合中的元素进行类型限定,将原来可能发生的运行时问题转换成编译时问题-即编译时检查.
            * 泛型是提供给javac编译器使用的,当编译通过,并最终生成class文件以后,将不再带有泛型信息,保证运行效率,这个过程叫类型擦除(type erasure).
            * 擦除是为了兼容jdk1.5以前的应用.
            * 只有对象类型才能作为泛型方法的实际参数.
        (2)    泛型是不斜变的
            List<Object> 不是 List<String> 的父类型
            而数组是不同
            Integer[] intArr = new Integer[10];
            Number[] numArr = intArr;
            上边代码是有效的,因为一个Integer是一个Number,因而一个Integer数组是一个Number数组.
            但是对于泛型来说不同:
                List<Integer> intList = new ArrayList<Integer>();
                List<Number> numList = intList;  //这句话是无效的
        (3)    类型通配符(可以解决不斜变问题)    
            示例:    
                void printList(List<?> l){
                    for(Object o : l){
                        System.out.println(o);
                    }
                }
            上面代码的问号是一个类型通配符.List<?>是任何泛型List的父类型,所以你可以完全将
            List<Object>、List<Integer等传递给pringList().
        (4)通配符扩展
            * 限定通配符的上边界:
                正确的:Vector<? extends Number> x = new Vector<Integer>();
                错误的:Vector<? extends Number> x = new Vector<String>();
            * 限定通配符的下边界:
                正确的:Vector<? super Integer> x = new Vector<Number>();
                错误的: Vector<? super Integer> x = new Vector<Byte>();
            * 限定通配符总是包括自己
                即:Vector<? extends Number> x = new Vector<Number>();
    7.注解
        (1)概述
            * 什么是注解
                要解释注解,需要先说一说什么是元数据(metadata).
                元数据就是数据的数据.也就是说,元数据是描述数据的.就像数据表中的字段一样,每个字段描述了这个字段下的数据的含义.
                j2se5.0中提供的注解就是java源代码的元数据,也就是说注解是描述java源代码的.
        (2)j2se5.0中预定义的注解(3个)
            * @Override
                此注解只可以注解在类的方法上,并且只在Source(即源码级别)级别可用.
                功能:可以保证编译时期覆盖父类函数的声明的正确性(可用来判断是否覆盖了父类方法).
                此注解定义源码:
                @Target(ElementType.METHOD)  //只能用于方法上
                @Retention(RetentionPolicy.SOURCE) //作用范围,仅在Source级别有效
                public @interface Override {
                }
            * @Deprecated
                使用该注解的元素,编译器会发出警告信息,提示方法已经过程.但并不影响程序运行.
                此注解源码:
                @Documented
                @Retention(RetentionPolicy.RUNTIME) //作用范围,运行时有效
                public @interface Deprecated {
                }
            * @SuppressWarnings
                上边的Deprecated是为了让编译器产生警告信息,而这个注解是为了不让编译器产生警告信息.
                功能:就是关闭特定的警告信息,例如使用集合的时候未指定泛型.
                其参数有:
                    deprecation:试用了过时的类或方法时的警告.
                    unchecked:执行了未检查的转换时的警告.
                    fallthrough: 当Switch程序块直接通往下一种情况而没有Break时的警告.
                    path: 在类路径、源文件路径等中有不存在的路径时的警告.
                    serial:当在可序列化的类上缺少serialVersionUID定义时的警告.
                    finally:任何finally子句不能正常完成时的警告.
                    all:关于以上所有情况的警告.
                示例:集合没有加泛型时会有提示,即下滑曲线(看着烦人).这时添加@SuppressWarnings (value={"unchecked"})会关闭警告.
                    此注解有属性,可以同时抑制多个警告,例如:@SuppressWarnings(value={"unchecked", "fallthrough"})
                注解源码:
                @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) //可以注解的范围
                @Retention(RetentionPolicy.SOURCE) //作用范围,源码级别
                public @interface SuppressWarnings {
                    String[] value();
                }
        (3)注解分类
            * 标记注解  : 没有变量,只有名称标识. @annotation
            * 单值注解 : 在标记注释的基础上提供一段数据. @annotation("data")
            * 完整注解 : 可以包括多个数据成员,每个数据成员由名称和值构成. @annotation(val1="data1",val2="data2")
        (4)j2se5.0内置的四种元注解
            * @Target : 表示该注解可以用于什么地方,可能的ElementType参数包括:
                    CONSTRUCTOR : 构造器的声明.
                    FIELD : 域声明(包括enum实例).
                    LOCAL_VARIABLE : 局部变量声明.
                    METHOD : 方法声明.
                    PACKAGE : 包声明.
                    PARAMETER : 参数声明.
                    TYPE : 类、接口(包括注解类型)或enum声明.
            * @Retention : 表示需要在什么级别保存该注解信息.可选的参数有:
                    SOURCE : 注解将被编译器丢弃
                    CLASS : 注解在class文件中可用,但会被vm丢弃.
                    RUNTIME : vm将在运行期也保留注释,因此可以通过反射机制读取注解的信息.
            * @Documented : 将此注解包含在Javadoc中.
            * Inherited : 允许子类继承父类中的注解.
        (5)自定义注解
            * 注解应用结构
                @interface A{..}  <---    @A            <--- Class C{..}
                                        Class B{..}    
                注解类                    用用了注解的类            对"应用了注解的类"
                                                                 进行反射操作的类,即注解的处理过程.
            * 示例:
                需求:写一个注解类@MyTest,功能类似Junit中的@Test.
                    动态接受需要运行的类名,然后运行所有被添加了注解的方法.
                代码:

//首先,注解类:
	@Retention(RetentionPolicy.RUNTIME)
	@Target(value=ElementType.METHOD)
	public @interface MyTest {
	}
//其次,测试类:
	public class TestOne {
		@MyTest
		public void abc(){
			System.out.print("abc");
		}
		@MyTest
		public void def(){
			System.out.print("def");
		}
		public void hello(){
			System.out.print("hello");
		}
	}
//最后,注解处理类:
	public class MyTestMain {
		public static void main(String[] args)throws Exception {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("输入要测试的类"); //输入TestOne的完全限定名
			String clazzName = br.readLine();
			Class clazz = Class.forName(clazzName);
			Object obj = clazz.newInstance();
			Method[] methods = clazz.getMethods();
			for(Method m : methods){
				if(m.isAnnotationPresent(MyTest.class)){
					m.invoke(obj);  //最后输出 abcdef,即添加了@MyTest注解的方法被执行了.
				}
			}
		}
	}



你可能感兴趣的:(JDK5.0新特性)