JDK5中新增了很多新的java特性,利用这些新语法可以帮助开发人员编写出更加高效、清晰,安全的代码。

这些新特性主要有:
1.静态导入
2.自动装箱/拆箱
3.增强for循环
4.可变参数
5.枚举
6.泛型
7.元数据

1.静态导入
静态导入用于简化程序对静态属性和方法的调用

语法:Import static 包名.类名.静态属性|静态方法|*
例如:
import static java.lang.System.out
import static java.lang.Math.*

2.自动装箱/拆箱
自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类。
自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型。

Integer i = 1; //装箱
int j = i; //拆箱

典型应用:
List list = new ArrayList();
list.add(1);
int j=(Integer)list.get(0);//拆箱

3.增强for循环

引入增强for循环的原因:在JDK5以前的版本中,遍历数组或集合中的元素,需要先获得数组的长度或集合的迭代器,比较麻烦!

JDK5中定义了一种新的语法--增强for循环,以简化此类操作。增强for循环只能在数组或实现Iterable接口的集合类上。

语法格式:
for(变量类型 变量:需要迭代的数组或集合){
}

代码:
@Test
public void test1() {
int arr[] = { 1, 2, 3 };
for (int num : arr) {
System.out.println(num);
}
}

输出:
1
2
3

@Test
public void test2() {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
for (Object obj : list) {
int i=(Integer)obj;
System.out.println(i);
}
}

输出:
1
2
3

@Test
public void test3() {
Map map=new HashMap();// HashMap按hash函数保存数据,保存的数据与存的顺序可能不一样
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");

//传统方式1
Set set=map.keySet();
Iterator it =set.iterator();
while(it.hasNext()){
String key=(String)it.next();
String value=(String)map.get(key);
System.out.println(key+"="+value);
}

}

输出:
3=ccc
2=bbb
1=aaa

@Test
public void test4() {
Map map=new LinkedHashMap();
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");

//传统方式1
Set set=map.keySet();
Iterator it =set.iterator();
while(it.hasNext()){
String key=(String)it.next();
String value=(String)map.get(key);
System.out.println(key+"="+value);
}

}

输出:
1=aaa
2=bbb
3=ccc

@Test
public void test5() {
Map map = new LinkedHashMap();
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");

// 传统方式2
Set set = map.entrySet();
Iterator it = set.iterator();
while (it.hasNext()) {
Map.Entry entry = (Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + "=" + value);
}

}

输出:
1=aaa
2=bbb
3=ccc

@Test
public void test6() {
Map map = new LinkedHashMap();
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");

// 增强for取map的第1种方式
for (Object obj : map.keySet()) {
String key = (String) obj;
String value = (String) map.get(key);
System.out.println(key + "=" + value);
}

}

输出:
1=aaa
2=bbb
3=ccc

@Test
public void test7() {
Map map = new LinkedHashMap();
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");

// 增强for取map的第2种方式
for (Object obj : map.entrySet()) {
Map.Entry entry = (Entry) obj;
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + "=" + value);
}

}

输出:
1=aaa
2=bbb
3=ccc

// 使用增强for需要注意的问题:增强for只适合取数据,要修改数组或集合中的数据,要用传统方式
@Test
public void test8() {
int arr[]={1,2,3};
for(int i:arr)
{
i=10;
}
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);

List list = new ArrayList();
list.add("1");
for(Object obj:list)
{
obj=10;
}
System.out.println(list.get(0));
}

输出:
1
2
3
1

4.可变参数

测试JDK中具有可变参数的类Arrays.asList()方法。分别传多个参、传数组,传数组又传参的情况。
注意:传入基本数据类型数组的问题

从JDK5开始,Java允许为方法定义长度可变的参数。语法:
public void foo(int ...args){
}

注意事项:
调用可变参数的方法时,编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以数组的形式访问可变参数

可变参数只能处于参数列表的最后,所以一个方法最多只能有一个长度可变的参数

代码:
@Test
public void testSum() {
sum(1,2,3,4,5,6);
}

public void sum(int ...nums) {
//可变参数你把他看成数组
int sum=0;
for(int i:nums){
sum+=i;
}
System.out.println(sum);
}

输出:
21

@Test
public void testAa() {
aa(1,2,3,4,5,6);
}

//可变参数需要注意的问题:public void aa(int ...nums,int x) { 这样不行,参数会被直接看成一个数组,x没有值
public void aa(int x,int ...nums) {
//可变参数你把他看成数组
int sum=0;
for(int i:nums){
sum+=i;
}
System.out.println(sum);
}

输出:
20

@Test
public void bb(){
List list=Arrays.asList("1","2","3");
System.out.println(list);

String arr[]={"1","2","3","4"};
list = Arrays.asList(arr);
System.out.println(list);

int nums[]={1,2,3,5};//这个细节一定要小心,注意可变参数类型,int nums[]是基本类型数组,这个数组就是一个对象,Arrays.asList(nums)的参数是对象集合。
list=Arrays.asList(nums);
System.out.println(list);
}

输出:
[1, 2, 3]
[1, 2, 3, 4]
[[I@1e63e3d]

5.枚举

1).枚举的作用
一些程序在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,jdk5以前采用自定义类来解决,jdk5以后可以直接采用枚举解决。

JDK5新增的enum关键字用于定义一个枚举类。

一个枚举也可以有构造函数、字段和方法。

2).枚举类具有如下特性:

枚举类也是一种特殊形式的Java类。

枚举类中声明的每一个枚举值代表枚举类的一个实例对象。

与Java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的(这点不难理解)。

枚举类也是可以实现接口或继承抽象类。

JDK5中扩展了swith语句,它除了可以接收int,byte,char,short外,还可以接收一个枚举类型。

若枚举类只有一个枚举值,则可以当作单态设计模式使用。

Java中声明的枚举类,均是java.lang.Enum类的孩子,它继承了Enum类的所有方法。常用方法:
name()
ordinal()
valueof(Class enumClass,String name)
values()此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它用于遍历枚举的所有枚举值。

代码:
1>.
@Test
public void test() {
print(Grade.B);
}

public void print(Grade g) {
String value = g.getValue();
System.out.println(value);
}

// 如何定义枚举的构造函数、方法和字段,去封装更多的信息
enum Grade {
A("100-90"), B("89-80"), C("79-70"), D("69-60"), E("59-0");

private String value;// 封装每个对象对应的分数

private Grade(String value) {
this.value = value;
}

public String getValue() {
return this.value;
}
}

输出:
89-80

2>.
@Test
public void test() {
print(Grade.B);
}

public void print(Grade g) {
String value = g.localValue();
System.out.println(value);
}

//带抽象方法的枚举
enum Grade {
A("100-90") {
public String localValue() {
return "优";
};
},
B("89-80") {
public String localValue() {
return "良";
};
},
C("79-70") {
public String localValue() {
return "一般";
};
},
D("69-60") {
public String localValue() {
return "差";
};
},
E("59-0") {
public String localValue() {
return "不及格";
};
};

private String value;// 封装每个对象对应的分数

private Grade(String value) {
this.value = value;
}

public String getValue() {
return this.value;
}

public abstract String localValue();
}

输出:

3>.测试枚举的常用方法
@Test
public void test2(){
System.out.println(Grade.C.name());
System.out.println(Grade.C.ordinal());

String str="B";
//Grade g=Grade.valueOf(Grade.class,str);
Grade g=Grade.valueOf(str);//str给出的值若无效则会报错
System.out.println(g);

Grade gs[]=Grade.values();
for(Grade g1:gs){
System.out.println(g1);
}

}

输出:
C
2
B
A
B
C
D
E

6.泛形(Generic)

1)泛形的作用

JDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换,这样不可避免就会引发程序的一些安全性问题。例如:

ArrayList list=new ArrayList();
list.add("abc");
Integer num=(Integer)list.get(0);//运行时会出错,但编码时发现不了

JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。示例。

List<String> list1=new ArrayList<String>();
list1.add("aaaa");
String s=list1.get(0);

2)掌握泛形的基本使用

掌握泛形集合的存取

3)泛形的几个注意事项

使用泛形时几个常见问题:

使用泛形时,泛形类型须为引用类型,不能是基本数据类型
ArrayList<Object> list=new ArrayList<String>();//错
ArrayList<String> list=new ArrayList<Object>();//错
ArrayList<String> list=new ArrayList();//对
ArrayList list=new ArrayList<String>();//对
用泛形时,如果两边都使用到泛形,两边必须要一样

注意:泛形是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

泛形的基本术语,以ArrayList<E>为例:<>念typeof
ArrayList<E>中的E称为类型参数变量
ArrayList<Integer>中的Integer称为实际类型参数
整个称为ArrayList<E>泛形类型
整个ArrayList<Integer>称为参数化的类型ParameterizedType

4)自定义泛形---泛形方法
Java程序中的普通方法、构造方法和静态方法中都可以使用泛形。
方法使用泛形前,必须对泛形进行声明,语法:<T>,T可以是任意字母,但通常必须要大写。<T>通常需要放在方法的返回值声明之前。例如:
public static <T> void doxx(T t);

练习:

编写一个泛形方法,实现指定位置上的数组元素的交换。(代码3)

编写一个泛形方法,接收一个任意数组,并颠倒数组中所有元素。(代码3)

注意:

只有对象类型才能作为泛形方法的实际参数。
在泛形中可以同时有多个类型,例如:
public static <K,V> V getValue(K key){return map.get(key);}

5)自定义泛形---泛形类和反射泛形

如果一个类多处都要用到同一个泛形,这时可以把泛形定义在类上(即类级别的泛形),语法格式如下:
public class GenericDao<T>{
private T field1;
public void save(T obj){}
public T getId(int id){}
}

注意,静态方法不能使用类定义的泛形,而应单独定义泛形。
泛形的典型应用:BaseDao和反射泛形

public BaseDao(){
Type type=this.getClass().getGenericSuperclass();
ParameterizedType pt=(ParameterizedType)type;
class=(Class)pt.getActualTypeArguments()[0];
}

6)

代码1:

package cn.itcast.generic;

//自定义带泛形的方法
public class Demo2 {

public void testa(){
a("aaa");
}

public <T> T a(T t){
return null;
}

public <T,E,K> void b(T t,E e,K k){

}
}

代码2:

package cn.itcast.generic;

//自定义类上的泛形
//类上面声明的泛形作用于整个类,静态方法上的泛形需要单独声明
public class Demo3<T,E,K> {

public void testa(){

}

public T a(T t){
return null;
}

public void b(T t,E e,K k){

}

public static <T> void c(T t){

}
}

代码3:

package cn.itcast.generic;

public class Demo4 {

// 编写一个泛形方法,实现指定位置上的数组元素的交换
public <T> void swap(T arr[], int pos1, int pos2) {
T temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}

// 编写一个泛形方法,接收一个任意数组,并颠倒数组中所有元素。
public <T> void reverse1(T arr[]) {
int start = 0;
int end = arr.length - 1;

while (true) {
if (start >= end)
break;

T temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;

start++;
end--;
}
}

public <T> void reverse2(T arr[]) {
int lenth = arr.length;
for (int i = 0; i < lenth / 2; i++) {
T temp = arr[i];
arr[i] = arr[lenth - i - 1];
arr[lenth - i - 1] = temp;
}
}
}

05-01 00:49