JDK1.5新特性

1、泛型(Generic)

一、概述:
    1)JDK5.0版本之后出现的新特性,用于解决安全问题,是一个类型安全机制。
java

    2)JDK1.5的集合类但愿在定义集合时,明确代表你要向集合中装入那种类型的数据,没法加入指定类型之外的数据。 程序员

    3)泛型是提供给javac编译器使用的能够限定集合中的输入类型说明的集合时,会去掉“类型”信息,使程序运行效率不受影响,对参数化的泛型类型,getClass()方法的返回值和原始类型彻底同样。 数组

    4) 没有使用泛型时,只要是对象,无论是什么类型的对象,均可以存储进同一个集合中。使用泛型集合,能够将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全;而且当从集合获取一个对象时,编译器也能够知道这个对象的类型,不须要对对象进行强制类型转换,这样更方便。泛型就是把原来的类名进行了延长<在JDK 1.5中,你还能够按原来的方式将各类不一样类型的数据装到一个集合中,但编译器会报告unchecked警告。
Note:
    1)因为编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就能够往某个泛型集合中加入其它类型的数据,如用反射获得集合,再调用add方法便可。
    2) 在使用java提供的对象时,何时写泛型? 缓存

    一般在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的。当使用集合时,将集合中要存储的数据类型做为参数传递到<>中便可。 安全

二、格式:

    经过<>来定义要操做的引用数据类型 框架

    如:ArrayList<String> = new ArrayList<String>();     //定义要存入集合中的元素指定为String类型 eclipse

三、优势: ide

    a、将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题。让运行时期问题减小、安全。 函数

    b、避免了强制转换的麻烦。如在实现某一个接口时,指定传入接口方法的实参的类型的话,在复写该接口方法时就能够直接使用指定类型,而不须要强制转换。 工具

四、术语:

    如:ArrayList<E>类和ArrayList<Integer>

    一、ArrayList<E>整个称为泛型类型

    二、ArrayList<E>中的E称为类型变量或类型参数

    三、整个ArrayList<Integer>称为参数化类型

    四、ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数

    五、ArrayList<Integer>中的<>称为typeof

    六、ArrayList称为原始类型

    七、参数化:parametered,已经将参数变为实际类型的状态。

五、参数化类型的说明:

    1)参数化类型与原始类型的兼容性(原来的方法接受一个集合参数,新类型也要能传进去

        a、参数化类型可引用一个原始类型的对象,编译只是报警告。

            如:Collection<String>coll = new Vector();

        b、原始类型可引用一个参数化类型的对象,编译报告警告

            如:Collectioncoll = new Vector<String>();  

    2)参数的类型不考虑类型参数的继承关系:

        Vector<String> v = newVector<Objec>();//错误的

        Vector<Objec> v = newVector<String>();//错误的,不写Object没错,写了就是明知故犯

    3)编译器不容许建立泛型变量的数组。即在建立数组实例时,数组的元素不能使用参数化的类型

        如:Vector<Integer>vectorList[] = new Vector<Integer>[10];//错误的

六、泛型限定:(用于泛型扩展)
通配符:
    ? 能够理解为占位符。类型不明确时使用,不能使用类型特有方法,例如length()方法。
     T 表明具体类型,能够接收并操做这个类型。
    ? extends E:  能够接收 E 类型或者 E 的子类型,上限。
    ? super E: 能够接收 E 类型或者 E 的父类型,下限。
Note:如下是错误的写法。集合(对象)的泛型的类型左右两边要一致。经过上限或者下限来解决。
        ArrayList<Person> al1 = new ArrayList<Student>();
        TreeSet< Student > al = new TreeSet < Person >();
示例以下:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

//动物  父类
class Animal {
	private String name;

	Animal(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
}

// 猫 继承父类
class Cat extends Animal {
	Cat(String name) {
		super(name);
	}
}

public class GenericTest {
	public static void main(String[] args) {
		ArrayList<Animal> al = new ArrayList<Animal>();
		al.add(new Animal("abc1"));
		al.add(new Animal("abc2"));
		al.add(new Animal("abc3"));
		printColl(al);// 父类对象的元素集合能够调用

		ArrayList<Cat> al1 = new ArrayList<Cat>();
		al1.add(new Cat("abc--1"));
		al1.add(new Cat("abc--2"));
		al1.add(new Cat("abc--3"));
		printColl(al1); // 子类对象的元素集合也能够调用
	}

	// 定义一个上限的泛型方法
	public static void printColl(Collection<? extends Animal> al) {
		Iterator<? extends Animal> it = al.iterator();
		while (it.hasNext()) {
			System.out.println(it.next().getName());
		}
	}
}

七、泛型类

1)若类实例对象中要使用到同一泛型参数,即这些地方引用类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型。

2)何时定义泛型类

    当类中要操做的引用数据类型不肯定的时候,早期定义Object来完成扩展。如今定义泛型来完成扩展。

3)泛型类定义的泛型,在整个类中有效。若是被方法使用,那么泛型类的对象明确要操做的具体类型后,因此要操做的类型就已经固定了。

4)类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,以下两种方式均可以:

    GenericDao<String>dao = null;

    newgenericDao<String>();

5)语法格式:

       class Utils<TT>{

             private TT s;

             public void settt(TT s){

                 this.s=s;

             }

             public TT getTT(){

                  return s;

             }

        }

Note:

    a、在对泛型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。

    b、当一个变量被声明为参数时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用,由于静态成员是被全部参数化的类共享的。

八、泛型方法

概述:为了让不一样方法能够操做不一样类型,并且类型还不肯定,那么能够将泛型定义在方法上。其中方法上的泛型能够不和类泛型相同,静态方法不能够访问类上定义的泛型,但若是静态方法操做的应用数据类型不肯定,能够将泛型定义在方法上。

特色:

     1)位置:用于放置泛型的类型参数的<>应出如今方法的其余全部修饰符以后和在方法的返回类型以前,也就是紧邻返回值以前,按照惯例,类型参数一般用单个大写字母表示。

     2)只有引用类型才能做为泛型方法的实际参数。

     3)除了在应用泛型时可使用extends限定符,在定义泛型时也可使用extends限定符。
        例如:Class.getAnnotation()方法的定义。而且能够用&来指定多个边界,如<V extends Serializable& cloneable> void method(){}。 

     4) 普通方法、构造函数和静态方法中均可以使用泛型。

     5) 能够用类型变量表示异常,称之为参数化的异常,可用于方法的throws列表中,可是不能用于catch子句中。

     6) 在泛型中可同时有多个类型参数,在定义它们的<>中用逗号分开。
        例如:
public static <K,V> V getValue(K key) { return map.get(key);}
示例以下:

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;

/*
 * 泛型限制:
 * ? 通配符,能够理解为占位符
 * ?  extends E:  能够接收 E 类型或者 E 的子类型。上限。
 * ?  super E:  能够接收 E 类型或者 E 的父类型。下限。
 */
class Person {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	Person(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}

}

class Student extends Person {

	Student(String name) {
		super(name);
	}

	@Override
	public String toString() {
		return "Student [name=" + getName() + "]";
	}

}

public class GenericDemo2 {

	public static void main(String[] args) {
		ArrayList<String> al1 = new ArrayList<String>();
		al1.add("abcd");
		al1.add("efg");
		al1.add("xyz");

		System.out.println("---------printElement1(al1)----------");
		printElement1(al1);
		// printElement2(al2);

		ArrayList<Person> al = new ArrayList<Person>();
		al.add(new Person("zhangsan"));

		al.add(new Student("li"));

		System.out.println("---------printElement1(al)----------");
		printElement1(al);
	}

	public static <T> void printElement1(ArrayList<T> al) {
		Iterator<T> it = al.iterator();
		while (it.hasNext()) {
			T t = it.next();
			t.toString();
			System.out.println(t);
		}
	}

	public static void printElement2(ArrayList<? extends Person> al) {
		Iterator<? extends Person> it = al.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}

}

T和?有什么区别:

    1)T限定了类型,传入什么类型即为何类型,能够定义变量,接收赋值的内容。

    2)?为通配符,也能够接收任意类型可是不能够定义变量。

    可是这样定义,虽然提升了扩展性,可仍是有一个局限性,就是不能使用其余类对象的特有方法。通配符方案要比泛型方法更有效,当一个类型变量用来表达两个参数之间或参数和返回值之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体代码中也被使用,而不是仅在签名的时候使用,才须要使用泛型方法。

Note:泛型的定义

    1)定义泛型:当又不肯定的类型须要传入到集合中,须要定义泛型。

    2)定义泛型类:若是类型肯定后,所操做的方法都是属于此类型,则定义泛型类。

    3)定义泛型方法:若是定义的方法肯定了,里面所操做的类型不肯定,则定义泛型方法。

九、类型参数的类型推断

1)编译器判断范型方法的实际类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种很是复杂的过程。

2)根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则以下:

    a、当某个类型变量只在整个参数列表中的全部参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用类型来肯定,这很容易凭着感受推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:

       swap(new String[3],3,4)

           ——>    static <E> voidswap(E[] a,int i,int j)

    b、当某个类型变量在整个参数列表中的全部参数和返回值中的多处被应用了,若是调用方法时这多处的实际应用类型都对应同一种类型来肯定,这很容易凭着感受推断出来,例如:

       add(3,5)

           ——>   static<T> T add(T a,T b)

    c、当某个类型变量在整个参数列表中的全部参数和返回值中的多处被应用了,若是调用方法时这多处的实际应用类型对应到了不一样的类型,且没有使用返回值,这时候取多个参数中的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题:

       fill(new Integer[3],3.5f)

           ——>    static<T> void fill(T[] a,T v)

    d、当某个类型变量在整个参数列表中的全部参数和返回值中的多处被应用了,若是调用方法时这多处的实际应用类型对应到了不一样的类型,而且使用返回值,这时候优先考虑返回值的类型,例如,下面语句实际对应的类型就是Integer了,编译将报告错误,将变量x的类型改成float,对比eclipse报告的错误提示,接着再将变量x类型改成Number,则没有了错误:

       intx =(3,3.5f)

           ——>   static<T> T add(T a,T b)

    e、参数类型的类型推断具备传递性,下面第一种状况推断实际参数类型为Object,编译没有问题,而第二种状况则根据参数化的Vector类实例将类型变量直接肯定为String类型,编译将出现问题:

       copy(newInteger[5],new String[5])

           ——>   static<T> void copy(T[] a,T[]  b);

       copy(newVector<String>(), new Integer[5])

           ——>   static<T> void copy(Collection<T> a ,T[] b);
2、枚举
一、概述:枚举是JDK1.5出现的新特性,字面意思理解就是,枚举中的元素是有限的,能够一一列举出来。

二、枚举的由来:

    问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即便使用常量方式也没法阻止意外。

    解决方案:枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,不然,编译器就会报错。枚举可让编译器在编译时就能够控制源程序中填写的非法值,普通变量的方式在开发阶段没法实现这一目标。
示例:

/*
 * 用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。 
 一、私有的构造方法
 二、每一个元素分别用一个公有的静态成员变量表示
 三、能够有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。
 */

abstract class WeekDay {
	private WeekDay() {
	}

	public final static WeekDay SUN = new WeekDay() {
		public WeekDay nextDay() {
			return MON;
		}
	};

	public final static WeekDay MON = new WeekDay() {
		public WeekDay nextDay() {
			return SUN;
		}
	};

	public abstract WeekDay nextDay();

	public String toString() {
		return this == SUN ? "SUM" : "MON";
	}
}

public class WeekDayDemo {

	public static void main(String[] args) {

		// 只能获取WeekDay中指定的值,不然会出错
		String today = WeekDay.MON.toString();
		// WeekDay.MON内部实现了WeekDay的nextDay方法,因此有返回值
		String nextDay = WeekDay.MON.nextDay().toString();
		System.out.println("today is " + today + ",nextDay is " + nextDay);
	}
}
Note:

    1)经过enum关键字定义枚举类,枚举类是一个特殊的class,每一个元素都是该类的一个实例对象。

    2)用枚举类规定值,如上面的WeekDay类。之后用此类型定义的值只能是这个类中规定好的那些值,若不是这些值,编译器不会经过。

    3)好处:在编译时期就会发现错误,代表值不符合,减小了运行时期的错误。

    4)若是调用者想打印枚举类中元素的信息,需由编写此类的人定义toString方法。

三、经常使用方法:

构造器:

    1)构造器只是在构造枚举值的时候被调用。

    2)构造器只有私有private,毫不容许有public构造器。这样能够保证外部代码没法从新构造枚举类的实例

    3)构造器能够有多个,调用哪一个即初始化相应的值。

非静态方法:(全部的枚举类都继承了Enum方法)

    1)String toString() ;    //返回枚举量的名称

    2)int ordinal() ;        //返回枚举值在枚举类中的顺序,按定义的顺序排

    3)Class getClass();      //获取对应的类名

    4) String name();         //返回此枚举常量的名称,在其枚举声明中对其进行声明。

静态方法:

    1)valueOf(String e) ;    //转为对应的枚举对象,即将字符串转为对象

    2)values() ;             //获取全部的枚举对象元素
示例以下:

public class EnumDemo {
	public static void main(String[] args) {
		WeekDay weekDay = WeekDay.SUN;
		System.out.println(weekDay);// 输出枚举常量名
		System.out.println(weekDay.name());// 输出对象名
		System.out.println(weekDay.getClass());// 输出对应类
		System.out.println(weekDay.toString());// 输出枚举对象名
		System.out.println(weekDay.ordinal());// 输出此对象在枚举常量的次序
		System.out.println(WeekDay.valueOf("WED"));// 将字符串转化为枚举常量
		System.out.println(WeekDay.values().length);// 获取因此的枚举元素,并打印其长度
	}
	// 定义枚举内部类
	public enum WeekDay {
		SUN(1), MON, TUE, WED, THI, FRI, SAT;// 分号无关紧要,但若是下面还有方法或其余成员时,分号不能省。
		// 并且当有其余方法时,必须在这些枚举变量的下方。

		// 无参构造器
		private WeekDay() {
			System.out.println("无参构造器");
		}

		// 有参构造器
		private WeekDay(int day) {
			System.out.println("有参构造器");
		}
	}
}
结果以下:

四、枚举的高级应用

1)枚举就至关于一个类,其中也能够定义构造方法、成员变量、普通方法和抽象方法。

2)枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其余成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。

3)带构造方法的枚举

    a、构造方法必须定义成私有的

    b、若是有多个构造方法,该如何选择哪一个构造方法?

    c、枚举元素MON和MON()的效果同样,都是调用默认的构造方法。

4)带方法的枚举

示例以下:
/*
 * 抽象的枚举方法
 * 此时枚举中的常量须要子类来实现,这是能够利用内部类的方式来定义枚举常量
 * 带方法的枚举
 1)定义枚举TrafficLamp
 2)实现普通的next方法
 3)实现抽象的next方法:每一个元素分别是由枚举类的子类来生成的实例对象,这些子类
 4)用相似内部类的方式进行定义。
 5)增长上表示时间的构造方法
 * */

public class TrafficLampDemo {
	public enum TrafficLamp {
		RED(30) {
			public TrafficLamp nextLamp() {
				return GREEN;
			}
		},
		GREEN(30) {
			public TrafficLamp nextLamp() {
				return YELLOW;
			}
		},
		YELLOW(5) {
			public TrafficLamp nextLamp() {
				return RED;
			}
		};
		private int time;

		// 构造器
		private TrafficLamp(int time) {
			this.time = time;
		}

		// 抽象方法
		public abstract TrafficLamp nextLamp();
	}
}

Note:

    1)匿名内部类比较经常使用

    2)类的方法返回的类型能够是本类的类型

    3)类中可定义静态常量,常量的结果就是本身这个类型的实例对象

    4)枚举只有一个成员时,就能够做为一种单例的实现方式
3、注解

一、概述

    1)注解(Annotation)至关于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记。之后,javac编译器、开发工具和其余程序能够用反射来了解你的类及各类元素上有无何种标记,看你有什么标记,就去干相应的事。

    2)标记能够加在包,类,字段,方法,方法的参数以及局部变量上。

    3)在java.lang包中提供了最基本的注解(annotation)。

    4)格式:@注解类名。

       若是只有一个value名称的属性或其余属性缺省,则可@注解名(”属性值”);

       若是有多个或不缺省或者需从新赋值,则@注解名(属性名=”属性值”,…)。

二、java中三种最基本的注解

    1)如@SuppressWarning(”deprecation”):表示压制过期警告;或者说不要警告过期提示。SupressWarning是告知编译器或开发工具等不须要再提示指定的警告了;deprecation”是警告的信息,即过期警告。

    2)@Deprecated:表示告知调用者,该成员函数、字段等已通过时,再也不推荐使用。源代码标记@Deprecated是在JDK1.5中做为内置的annotation引入的,用于代表类(class)、方法(method)、字段(field)已经再也不推荐使用,而且在之后的JDK版本中可能将其删除,编译器在默认状况下检测到有此标记的时候会提示警告信息。例如:假定以前的某个类升级了,其中的某个方法已通过时了,不可以将过期的方法删除,由于可能会影响到以前调用此这个方法的某些程序,这时就能够经过在方法上加这个注解来标记。

    3)@Override:表示下面的方法是在覆盖(父类方法),若是不存在覆盖,就会报错。加上此注解,可对类中的方法判断是不是要覆盖的父类的方法。典型的例子即在类中覆盖equals(Object obj)方法时,其中的参数类型必须是Object,才能被覆盖;若不是,则不存在覆盖。此时若是加上了此注解就会提示警告。

三、注解的应用结构图

      

Note:注解就至关于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先准备好了这个注解类。就像你要调用某个类,得先有开发好这个类。

四、自定义注解及其应用

1)定义格式:@interface名称{statement}

    如:最简单的注解类:public @interface MyAnnotation{}

2)元注解(注解的注解)

    即在定义注解类的时候加注解。如两个经常使用于元注解的注解:Retention和Target

    1)Retetion:用于说明注解保留在哪一个阶段(即注解的生命周期)。

    一个注解的生命周期包含:java源程序--(javac)-->class文件--(类加载器)-->内存中的字节码分别对应Retetion这个枚举类的值:

        RetetionPolicy.SOURSE:java源文件时期,如@Overried和@SuppressWarning

        RetetionPolicy.CLASS: class文件时期(默认阶段)

        RetetionPolicy.RUNTIME:运行时期,如@Deprecated

Note:a)当在源程序上加了注解,javacjava源程序编译为class文件时,会对注解的生命周期进行判断。若是该注解只保留在源程序,则编译时会将该注解进行相应的处理操做b)class文件中不是字节码,只有把class文件中的内容加载进内存,用类加载器加载处理后(进行完整的检查等处理),最终获得的二进制内容才是字节码,

    2)Target:用于说明注解类的使用范围。如在方法上仍是类上,默认值是任何地方。

    其值可设置为枚举类ElementType类中的任何一个,包括:包、字段、方法、方法参数、构造器、类等值。取值为:

         PACKAGE(包声明)

         FIELD(字段声明)

         ANNOTATION_TYPE(注释类型声明)

         CONSIRUCTOR(构造器声明)

         METHOD(方法声明)

         PARAMETER(参数声明)

         TYPE(类、接口(包含注释类型)或枚举声明)

         LOCAL_VARIABLE(局部变量声明)

Note:其中表明类的值是TYPE。由于class、enum、interface和@interface等都是平级的,因此统属于Type,不可用CLASS表示。

3)注解的应用

    经过反射方式来获取自定义的注解类,步骤跟注解的应用结构一致。

    如:

       第1、定义注解类:@interfaceA{}

       第2、应用了“注释类”的类:@A  class B{}

       第3、对“应用注释类的类”进行反射操做的类:class c{...},操做以下:

             B.class.isAnnotionPresent(A.class);//判断是否存在此注解类

             A a = B.class.getAnnotation(a.class);//存在的话则获得这个注释类的对象 

五、为注解添加基本属性

1)属性:一个注解至关于一个胸牌,但仅经过胸牌还不足以区别带胸牌的两我的,这时就须要给胸牌增长一个属性来区分,如颜色等。

2)定义格式:同接口中的方法同样:String color();

     定义缺省格式:String value() default “heima”;

3)应用:直接在注解的括号中添加自身的属性,如:

    @MyAnnotation(color=”red”)

    1)若是注解中有一个名称为value的属性,且你只想设置value属性(即其余属性都采用默认值或者你只有一个value属性),那么能够省略value=部分,例如:@SuppressWarnings("deprecation")。

    2)能够为属性值指定缺省值(default),应用时一样能够从新设置属性值。

    3)用反射方式得到注解对应的实例对象后,能够经过该对象调用属性对应的方法来获取属性值。

六、为注解增长高级属性

1)能够为注解增长的高级属性的返回值类型有:

    1)八种基本数据类型   

    2)String类型 

    3)Class类型

    4)枚举类型  

    5)注解类型  

    6)前五种类型的数组

2)数组类型的属性:

    如:int[]arrayArr() default {1,2,3};//可不定义默认值

    应用:@MyAnnotation(arrayArr={2,3,4}) //可从新赋值

Note:若数组属性中只有一个元素(或从新赋值为一个元素),这时属性值部分可省略大括号。

3)枚举类型的属性:

    假设定义了一个枚举类TrafficLamp,它是EnumTest的内部类,其值是交通灯的三色。

    定义:EnumTest.TrafficLamplamp();

    应用:@MyAnnotation(lamp=EnumTestTrafficLamp.GREEN)

4)注解类型的属性:

    假定有个注解类:MetaAnnotation,其中定义了一个属性:String value()

    定义:MetaAnnotation annotation() default @MetaAnnotation(”xxx”);

    应用:@MyAnnotation(annotation=@MetaAnnotation(”yyy”))//从新赋值

能够认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象,一样的道理,能够认为上面这个@MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码以下:

    MetaAnnotationma =MyAnnotation.annotation();

    System.out.println(ma.value());

5)Class类型的属性:

    定义:Class cls();

    应用:@MyAnnotation(cls=AnnotationDemo.class)

Note:这里的.class必须是已定义的类,或是已有的字节码对象。

6)注解的详细语法可经过查看java语言规范了解即javaLanguage Specification

示例:
package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)//元注释
@Target({ElementType.METHOD,ElementType.TYPE})//元注解,指定使用范围
//注解类
public @interface MyAnnotation {
	String color() default "red" ;
	String value();
	//数组
	int[] arr() default {1,2,3};
	//枚举
	EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.GREEN;
	//注解类
	MetaAnnotation annotation() default @MetaAnnotation("heima");
	//Class类
	Class clazz() default System.class;
}

import java.lang.reflect.Method;

//注解类的应用,给属性赋值或者从新赋值
@MyAnnotation(lamp=EnumTest.TrafficLamp.YELLOW,value="heima",
			clazz=AnnotationDemo.class,annotation=@MetaAnnotation("itheima"))
//应用类
public class AnnotationDemo {
	@SuppressWarnings("deprecation")//此注解用于抑制过期信息的提示
	@MyAnnotation("Method")//自定义注解应用在方法上
	public static void main(String[] args) throws NoSuchMethodException, SecurityException {
		
		System.runFinalizersOnExit(true); //这是一个过期了的方法 ,若是没有注解就会有警告提示
		//判断此类是否有MyAnnotation注解
		if (AnnotationDemo.class.isAnnotationPresent(MyAnnotation.class)) {
			//若是有,则获取该注解
			MyAnnotation annotation =AnnotationDemo.class.getAnnotation(MyAnnotation.class);
			System.out.println(annotation);//@cn.itheima.Demo.MyAnnotation()
			System.out.println(annotation.color());//red
			System.out.println(annotation.value());//heima
			System.out.println(annotation.arr().length);//3
			System.out.println(annotation.lamp());//YEllOW
			System.out.println(annotation.annotation().value());//itheima
			System.out.println(annotation.clazz());//class cn.itheima.demo.AnnotationDemo
		}
		
		//获取方法上的注解
		Method mainMethod=AnnotationDemo.class.getMethod("main",String[].class);
		MyAnnotation annotationMethod=(MyAnnotation) mainMethod.getAnnotation(MetaAnnotation.class);
		SuppressWarnings sw=mainMethod.getAnnotation(SuppressWarnings.class);
		System.out.println(sw);//null
		System.out.println(annotationMethod);//null	
	}
}
4、加强for循环

一、格式:

    for( 数据类型  变量名 : 被遍历的集合(collection)或者数组 ) { 执行语句 }

二、说明:

    a、对集合进行遍历。只能获取集合元素。可是不能对集合进行操做。能够看做是迭代器的简写形式。

    b、迭代器除了遍历,还能够进行remove集合中元素的动做。若是使用ListIterator,还能够在遍历过程当中对集合进行增删改查的操做。

三、传统for循环和高加强or循环的区别:

    高级for有一个局限性。必须有被遍历的目标(集合或数组)。

    传统for遍历数组时有索引。

Note:
    1)加强for循环所迭代的是集合必须是数组或者是实现了Iterator接口的集合类。
    2)在遍历数组的时候要使用定义的角标,仍是建议使用传统for循环。
    3)变量类型前可加修饰符,如final(可被局部内部类访问到)。

示例:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ForInhance {

	public static void main(String[] args) {
		// 传统for与高级for遍历数组
		String[] arr = { "www", "itheima", "com" };

		for (int x = 0; x < arr.length; x++) {
			System.out.println(arr[x]);
		}
		for (String i : arr) {
			System.out.println("i:" + i);
		}

		// 定义一个HashMap集合
		HashMap<Integer, String> hm = new HashMap<Integer, String>();

		hm.put(1, "www");
		hm.put(2, "itheima");
		hm.put(3, "com");

		// keySet取出方式的高级for遍历
		Set<Integer> keySet = hm.keySet();
		for (Integer i : keySet) {
			System.out.println(i + "::" + hm.get(i));
		}

		// entrySet取出方式的高级for遍历
		for (Map.Entry<Integer, String> me : hm.entrySet()) {
			System.out.println(me.getKey() + "------" + me.getValue());
		}
	}
}

5、可变参数

一、概述:若是一个方法在参数列表中传入多个参数,个数不肯定,那么每次都要复写该方法。这时能够用数组做为形式参数。可是在传入时,每次都须要定义一个数组对象,做为实际参数。在JDK1.5版本开始,就提供了一个新特性:可变参数(VariableParameter)。

二、格式:用"…"这三个点表示,且这三个点位于变量类型和变量名之间,先后有无空格皆可。

Note:
    1) 可变参数其实就是数组参数的简写形式,不用每一次都手动的创建数组对象,只要将要操做的元素做为参数传递便可,隐式将这些参数封装成了数组。
    2) 在使用时注意:可变参数必定要定义在参数列表的最后面。

public class VariableParameterDemo {
	public static void main(String[] args) {
		int retVal = add(108, 109, 110, 111, 112, 113);
		System.out.println("总和为:" + retVal);
	}

	// ...表明多个参数
	public static int add(int x, int... args) {
		int sum = x;
		// 加强for循环
		for (int arg : args) {
			sum += arg;
		}
		return sum;
	}
}
6、静态导入

一、写法:

    import staticjava.util.Arrays.*;    //导入的是Arrays这个类中的因此静态成员。

    import staticjava.lang.System.*;    //导入了Ssytem类中因此静态成员。

    没加static导入的是类,加上static导入的全是某一个类中因此的静态成员,这样写在调用该类的静态方法时能够不用再写类名。如:Arrays.sort(数组);就能够直接写sort(数组);

Note:

    1)当导入的两个类中有同名成员时,须要在成员前加上相应的类名。

    2)当类名重名时,须要指定具体的包名。当方法重名时,指定具体所属的对象或者类。

示例:
import java.util.*;
import static java.util.Arrays.*;
import static java.lang.System.*;

class StaticImport // extends Object
{
	public static void main(String[] args) {
		out.println("itheima");// 打印输出时就能够直接省略书写System.
		int[] arr = { 3, 1, 5 };

		sort(arr);// 使用Arrays工具类的方法sort时就能够省略书写Array.

		int index = binarySearch(arr, 1);// 半分查找也是同样能够省略
		out.println("Index=" + index);

		// 当没有指定继承时,因此类默认继承了Object,
		// 由于toString方法都具有,因此为了区分,必须写上具体调用者
		out.println(Arrays.toString(arr));
	}
}
7、自动拆箱、自动装箱
概述:说到这个特性以前得说说包装类——基本数据类型所定义的应引类型称为基本数据类型的包装类。JDK1.5以前,基本数据类型与包装类之间的转换都得依靠指定的方法手动转换的,而JDK1.5以后,这些操做在使用的时候自动完成,其中包括自动装箱、自动拆箱。
使用:
    1)自动装箱:
      eg: Integer num = 1;

    2) 自动装箱:
      eg: num = num+2;

Note:对于基本数据类型的说明:整数在-128 ~ 127之间的数,包装成Integer类型对象,会存入常量池中的缓存,再建立一个对象的时候,若是其值在这个范围内,就会直接到常量池中寻找,由于这些小数值使用的频率很高,因此缓存到常量池中,被调用时就方便不少。
示例:

public class AutoDemo {

	public static void main(String[] args) {

		// 定义一个Integer类的书numa
		Integer numa = 1;//自定装箱
		int numc = numa + 1;//自动拆箱
		System.out.println(numc + "---" + numa.getClass().getName());
		// 定义第二个Integer数numb,所赋的值与numa相等
		Integer numb = 1;
		// 判断numa是否等于numb
		System.out.println("numa == numb\t" + (numa == numb));// true

		// 再的定义a、b,数字相等但都在-127~128范围外
		Integer a = 128;
		Integer b = 128;
		// 判断两个数是否相等
		System.out.println("a == b\t" + (a == b));// false
	}
}
    以上所述即JDK1.5主要的新特性,预知更多新特性可Google详解,上述仅表明我的观点,若有出入请谅解。
相关文章
相关标签/搜索