JDK5的一些新特性

时间:2022-01-28 15:16:53

一、泛型

* 为什么要使用泛型?
- 一般使用在集合上
** 比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放入到集合之后,失去本事的类型,只能是object类型,
这个时候,比如想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型来解决。

* 在集合上如何使用泛型
- 常用集合 list  set  map
- 泛型语法 集合<String>  比如 List<String>
* 在泛型里面写是一个对象,String 不能写基本的数据类型 比如int (****)
** 写基本的数据类型对应包装类

byte -- Byte
short -- Short
int -- Integer
long -- Long
float -- Float
double -- Double
char   -- Character

boolean -- Boolean

* 在List上使用泛型

List:有序,存入和取出的顺序一致,元素都有索引,元素可以重复

                    ArrayList :内部是数组数据结构,不同步。替代了Vector。查询速度快。

                    linkedList: 内部是链表数据结构,不同步。增删快。

                    Vector:内部是数组数据结构,是同步的。

//遍历list集合 有三种方式
//普通for循环  迭代器  增强for

		List<String> list=new ArrayList<String>();
		list.add("hello");
		list.add("world");
		list.add("java");
		//增强for遍历
		for (String s : list) {
			System.out.println(s);
		}
		System.out.println("-------------");
		//普通for遍历
		for(int i=0;i<list.size();i++){
			String s1=list.get(i);
			System.out.println(s1);
		}
		System.out.println("-------------");
		//迭代器迭代
		Iterator<String> it=list.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
* 在Set上使用泛型

Set:元素不能重复,无序 

                    HashSet:内部数据结构是哈希表,不同步

                    TreeSet:可以对Set集合中的元素进行排序,通过Comparable接口或覆盖comPareTo方法。

//遍历set 有两种方式

//迭代器  增强for

		Set<String> set = new HashSet<String>();
		set.add("hello");
		set.add("world");
		set.add("java");
		// 增强for
		for (String string : set) {
			System.out.println(string);
		}
		System.out.println("-------------");
		// 迭代器迭代
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
结果为:      (内部哈希算法排序,无序)
hello
java
world
-------------
hello
java
world
* 在map上面使用泛型

- map结构:key-value形式

                    Hashtable:内部结构是哈希表,同步。不允许null作为键和值。

                    HashMap:内部结构是哈希表,不同步。允许null作为键和值。

                    TreeSet:内部结构是二叉树,不同步。可以对Map集合中的键进行排序。

//遍历map有两种方式
//1、获取所有的key,通过key得到value 使用get方法
//2、获取key和value的关系

		Map<Integer, String> hm = new HashMap<Integer, String>();
		hm.put(1, "张三");
		hm.put(2, "李四");
		hm.put(3, "王五");
		//获取所有的key,遍历key获取value
		Set<Integer> set=hm.keySet();
		for (Integer integer : set) {
			System.out.println(integer+"---"+hm.get(integer));
		}
		System.out.println("-------------");
		//获取key和value的关系
		Set<Entry<Integer, String>> set2=hm.entrySet();
		for (Entry<Integer, String> entry : set2) {
			Integer key=entry.getKey();
			String value=entry.getValue();
			System.out.println(key+"---"+value);
		}

二、泛型定义在方法上

        public <T> void show(T str){        }

         * 写在返回值之前  void之前 <T>
        * 表示定义了一个类型 这个类型是 T
        * 在下面就可以使用这个类型了  T

* 定义一个数组,实现指定位置上数组元素的交换

        public static <T> void swap1(T[] arr ,int a,int b) {
        T temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;

        }

练习:实现一个泛型方法,接受任意一个数组,颠倒数组中所有元素

	public static void main(String[] args) {
		Integer[] integers = { 1, 2, 3, 4, 5, 6, 9, 15 };
		reverseArr(integers);
		String[] strings = { "hello", "world", "java" };
		reverseArr(strings);
	}

	public static <T> void reverseArr(T[] arr) {
		for (int i = 0; i < arr.length / 2; i++) {
			T t = arr[i];
			arr[i] = arr[arr.length - 1 - i];
			arr[arr.length - 1 - i] = t;
		}
		System.out.println(Arrays.toString(arr));
	}

三、泛型在类上的使用

* 在一个类上定义一个类型,这个类型可以在类里面直接使用
* public class TestDemo04<T> {

//在类里面可以直接使用T的类型
T aa;
public void test11(T bb) {}

//写一个静态方法 在类上面定义的泛型,不能再静态方法里面使用
public static <A> void test12(A cc) {}

}

四、泛型的通配符

        ?  :可以对类型进行限定

                ? extends E:接收E类型或者E类型的子类型对象        上限

                ? super E:接收E类型或者E类型的父类型                  下限

        一般存储元素的时候使用上限,因为这样取出都是按照上限类型来运算的。不会出现安全隐患。

        对集合中的元素进行取出操作时,用下限。

五、枚举的简介

* 什么是枚举?
** 需要在一定的范围内取值,这个值只能是这个范围内中的任意一个。
** 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个

* 使用一个关键字 enum
** enum Color{
RED,GREEN,YELLOW;
}
* 枚举的构造方法也是私有的

* 特殊枚举的操作(了解)
** 在枚举类里面有构造方法
** 构造方法里面有参数,需要在每个实例上面都写参数
** 在枚举类里面有抽象方法
** 在枚举的每个实例里面都重写这个抽象方法

六、枚举的API操作

** name() :返回枚举的名称
** ordinal() :枚举的下标,下标从0开始
** valueOf(Class<T> enumType, String name) :得到枚举的对象

** 还有两个方法,但是这两个方法不在api里面,编译的时候生成两个方法
*** valueof(String name)  转换枚举对象
*** values()  获得所有枚举对象数组

* 练习:枚举对象、枚举对象下标、枚举对象名称表示之间的转换
- //知道枚举的对象,得到枚举名称和下标
@Test
public void test1() {
//得到枚举对象
Color col = Color.RED;
//枚举名称
String name = col.name();
//枚举的下标
int idx = col.ordinal();
System.out.println(name+" "+idx);
}

- //知道枚举的名称,得到枚举的对象和下标
@Test
public void test2() {
String name1 = "GREEN";
//得到对象
Color col = Color.valueOf(name1);
//枚举下标
int idx1 = col.ordinal();
System.out.println(idx1);
}

- //知道枚举的下标,得到枚举的对象和名称
@Test
public void test3() {
int idx2 = 2;
//得到枚举的对象
Color[] cols = Color.values();
//根据下标得到对象
Color col = cols[idx2];
//得到枚举的名称
String name = col.name();
System.out.println(name);
}

七、静态导入(了解)

* 可以在代码里面,直接使用静态导入方式,导入静态方法或者常量
* import static XX.XX.xxx

import static java.lang.System.out;
import static java.util.Arrays.sort;
import static java.util.Arrays.toString;
public class TestDemo1 {
	public static void main(String[] args) {
		out.println("hello");
		int[] arr1 = {10,1,3,20,15};
		sort(arr1);
		//System.out.println(toString(arr1));
	}
}

八、自动拆装箱

* 装箱
** 把基本的数据类型转换成包装类
* 拆箱
** 把包装类转换成基本的数据类型


** //自动装箱
Integer i = 10;

//自动拆箱
int m = i;

** 在jdk1.4里面如何实现装箱和拆箱
- //在jdk1.4里面实现拆装箱
public void test1() {
//装箱
Integer m = new Integer(10);
//拆箱
int a = m.intValue();
}
** jdk是会向下兼容
- 比如 jdk1.4里面写的代码,这个时候到5.0里面也可以运行


** 练习:向下兼容
== 执行的结果是会调用  doSomething(double m)
== 首先在jdk1.4里面肯定调用这个方法,如果调用下面的方法,需要类型转换,但是jdk1.4不能实现自动拆装箱
== 由于jdk是向下兼容,所以,在jdk1.4调用这个方法,在jdk5.0里面还是会调用这个方法
public static void main(String[] args) {
doSomething(10);    //double......
}
public static void doSomething(double m) {
System.out.println("double......");
}
public static void doSomething(Integer a){
System.out.println("integer.....");

九、增强for循环

* 语法 for(变量类型  变量名: 要迭代的数组或集合) {}
- for(String s : list) {
System.out.println(s);
}
* 使用场景: 数组;实现Iterable接口的集合 可以使用增强for循环

* 在集合上使用增强for循环遍历
list  set 实现了Iterator接口,所以可以使用增强for循环
map不能使用增强for循环,没有实现Iterator接口,所以不能使用增强for循环
                        可以通过Map的entrSet方法或者KeySet方法现获取到Set集合在使用增强for
* 增强for循环出现目的:为了替代迭代器
** 增强for底层就是迭代器实现的

十、可变参数

* 可变参数可以应用在什么场景:
** 实现两个数的相加,实现三个数的相加 四个数的相加
-- 如果实现的多个方法,这些方法里面逻辑基本相同,唯一不同的是传递的参数的个数,可以使用可变参数

* 可变参数的定义方法:数据类型...数组的名称
* 理解为一个数组,这个数组存储传递过来的参数
- 代码
public static void add1(int...nums) {
//nums理解为一个数组,这个数组存储传递过来的参数
//System.out.println(nums.length);
int sum = 0;
//遍历数组
for(int i=0;i<nums.length;i++) {
sum += nums[i];
}
System.out.println( sum);
}

* 注意的地方
(1)可变参数需要写在方法的参数列表中,不能单独定义
(2)在方法的参数列表中只能有一个可变参数
(3)方法的参数列表中的可变参数,必须放在参数最后
- add1(int a,int...nums)