黑马程序员——集合——泛型、Collections和Arrays

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、泛型

了解泛型之前我们先看一下没有泛型会产生什么结果:

package com.leaf.test;
import java.util.ArrayList;
import java.util.List;
class  ListDemo
{
	public static void main(String[] args) 
	{
		List list = new ArrayList();
		list.add("abc");
		list.add("abc");
		list.add(new Integer(1));
		String str = (String)list.get(2);
	}
}
result:

定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于result中的错误。因为编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。

在我们平时的代码中,我们发现主要存在两个问题:

1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。

2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。

那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢?答案就是使用泛型。

泛型的基本使用:

示例(错误):


示例(正确):

import java.util.*;
/*
	泛型的最基本使用
*/
package com.leaf.generic;
import java.util.ArrayList;
import java.util.List;
class  GenericDemo
{
	public static void main(String[] args) 
	{
		List<String> list = new ArrayList<String>();
		list.add("abc");
		System.out.println(list);

	}
}
result:

泛型的定义:

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

泛型是提供给javac编译器使用的,可以限定集合输入的类型,让编译器挡住源程序的非法输入, 是程序的运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全 一样,由编译器生成的字节码文件会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可

泛型的原理及深层使用:泛型的术语、泛型的通配符、限定通配符

        泛型的术语:

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

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

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

          ArrayList<Integer>中的<>称为typeOf

         ArrayList称为原始类型

        参数化类型与原始类型的兼容性

          参数化类型可以引用一个原始类型的对象,编译报告警告,例如:

          Collection<String> c = new Vector();//可不可以就是编译器的一句话

            原始类型可以引用一个参数化类型的对象,编译器警告,例如:

         Collection c = new Vector<String>();

          参数化类型不考虑参数的继承关系

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

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

          在创建数组实例时,数组的元素不能使用参数化的类型,例如:

           Vector<Integer> vectorList[] = newVector<Integer>[10];

           下列代码可以:

           Collection c = newCollection<String>();

           Collection<Object> col = c;

         是不是看不懂上面这些东西,下面来写一个示例:

package com.leaf.generic;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;

public class GenericTest {
	public static void main(String[] args) throws NoSuchMethodException,
			SecurityException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		// 没有泛型的集合,会报警告
		ArrayList col = new ArrayList();
		col.add(1);
		// 会因为类型无法转换而报错
		// int i = (Integer)col.get(1);
		// 泛型的定义在字节码文件中会被去除
		ArrayList<Integer> col1 = new ArrayList<Integer>();

		ArrayList<String> col2 = new ArrayList<String>();
		// col.add(1);//报错,因为类型不匹配,Integer类型的数据无法存入定义了String类型泛型的集合中
		// col.add(1L);//同上
		col2.add("abc");
		String str = col2.get(0);

		System.out.println("col1和col2的字节码文件是一样的吗?-->"
				+ col1.getClass().equals(col2.getClass()));

		// 反射也可以定义泛型
		Constructor<String> con = String.class.getConstructor();
		String s = con.newInstance();
//		printCollection(col2);//定义了限定通配符,传入String类型泛型的集合就会报错
		printCollection(col1);
	}
	//通配符"?"表示任何类型       extends表示必须是Number或者Number的子类才可以,可以使用&限定多个类
	public static void printCollection(Collection<? extends Number> col){
		/*
		 * 使用通配符得到的集合不能使用add等与具体类型有关系的方法
		 * col.add(1)//错误,因为他不知道会匹配到什么类型
		 * 可以使用与类型无关的方法,如:size();
		 * 
		 * 使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要作用
		 * 是用做引用,可以调用与参数无关的方法,不能调用与参数有关的方法
		 */
		System.out.println(col.size());
	}
}
result:

示例2:一般情况下,编写代码能遇到的最复杂的泛型就是在使用Map集合的Map.Entry的时候了,如下述代码,你能看懂了,泛型对你来说也就算基本掌握了

package com.leaf.generic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class GenericTest1 {
	public static void main(String[] args) {
		Map<String,Integer> map = new HashMap<String,Integer>();
		map.put("zs",20);
		map.put("laobi", 23);
		map.put("zxx", 12);
		Set<Map.Entry<String,Integer>> set = map.entrySet();
		for(Iterator<Map.Entry<String, Integer>> it = set.iterator();it.hasNext();){
			Map.Entry<String, Integer> me = it.next();
			System.out.println(me.getKey()+":"+me.getValue());
		}
		Collection<String> col = new ArrayList<String>();
		col.add("a");
		col.add("b");
		col.add("c");
		addCollection(col, "d");
		System.out.println(col);
		String[] strArr = new String[4];
		copyColToArr(col, strArr);
		System.out.println(Arrays.asList(strArr));
	}
	public static <T> void addCollection(Collection<T> col,T t){
		col.add(t);	
	}
	public static <T> T[] copyColToArr(Collection<T> col,T[] arr){
		Iterator<T> it = col.iterator();
		int count = 0;
		while(it.hasNext()){
			T t = it.next();
			arr[count] = t;
			count++;
		}
		return arr;
	}
}
result:


二、Collections工具类:

示例:

对集合进行排序

package com.leaf.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class CollectionsDemo {
	public static void main(String[] args) {
		demo1();
	}

	public static void demo1() {
		List<String> list = new ArrayList<String>();

		list.add("abcde");
		list.add("bcda");
		list.add("cdsfe");
		list.add("sdfdefdfg");
		list.add("efdfg");
		list.add("hasfhfg");

		// 对list集合进行指定顺序的排序,使用collections提供的方法是按照list集合中的比较器比较,也就是按照字母的ASSIC码表的顺序
		Collections.sort(list);
		System.out.println(list);
		//对集合使用自定义的排序方式,使用集合中字符串的长度进行排序
		Collections.sort(list, new ComparatorByLength());
		System.out.println(list);
		//模拟写一个和collections中提供的方法一样的方法
		mySort(list, new ComparatorByLength());
		System.out.println(list);
	}

	public static <T> void mySort(List<T> list, Comparator<? super T> comp) {
		for (int i = 0; i < list.size() - 1; i++) {
			for (int j = i + 1; j < list.size(); j++) {
				if (comp.compare(list.get(i), list.get(j)) > 0) {
					Collections.swap(list, i, j);
				}
			}
		}
	}
}

class ComparatorByLength implements Comparator<String> {
	public int compare(String o1, String o2) {
		int temp = o1.length() - o2.length();
		return temp == 0 ? o1.compareTo(o2) : temp;
	}
}
result:

注:工具类,内部都是静态方法,直接使用Collections.方法名调用

示例:

package com.leaf.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class CollectionsDemo2 {

	public static void main(String[] args) {
		demo1();
	}
	public static void demo1() {
		List<String> list = new ArrayList<String>();

		list.add("abcde");
		list.add("bcda");
		list.add("cdsfe");
		list.add("sdfdefdfg");
		list.add("efdfg");
		list.add("hasfhfg");

		//寻找:
		int index = Collections.binarySearch(list, "bcda");
		System.out.println("index:"+index);
		
		//获取长度最长的字符串
		String max = Collections.max(list);
		System.out.println("max="+max);
	}
	class ComparatorByLength implements Comparator<String> {
		public int compare(String o1, String o2) {
			int temp = o1.length() - o2.length();
			return temp == 0 ? o1.compareTo(o2) : temp;
		}
	}
}
result:


示例:

package com.leaf.test;

import java.util.Collections;
import java.util.Comparator;
import java.util.TreeSet;

public class CollectionsDemo3 {
	public static void main(String[] args) {
		System.out.println("使用了Collections.reserseOrder(...)");
		demo3();
		System.out.println("未使用了Collections.reserseOrder(...)");
		demo4();
	}
	public static void demo4(){
		TreeSet<String> ts = new TreeSet<String>();
		ts.add("abc");
		ts.add("hahaha");
		ts.add("zzz");
		ts.add("aa");
		ts.add("cba");
		System.out.println(ts);
	}
	public static void demo3() {
		TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder());
		ts = new TreeSet<String>(
				Collections.reverseOrder(new ComparatorByLength1()));
		ts.add("abc");
		ts.add("hahaha");
		ts.add("zzz");
		ts.add("aa");
		ts.add("cba");
		System.out.println(ts);
	}
}

class ComparatorByLength1 implements Comparator<String> {
	public int compare(String o1, String o2) {
		int temp = o1.length() - o2.length();
		return temp == 0 ? o1.compareTo(o2) : temp;
	}
}
result:

示例:

package com.leaf.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionsDemo4 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("abc");
		list.add("b");
		list.add("cds");
		list.add("sdfde");
		list.add("abc");
		list.add("ha");
		System.out.println("-------------------------------------");
		demo5(list);
		System.out.println("-------------------------------------");
		demo6(list);
	}
	public static void demo5(List<String> list){
		//replaceAll方法
		System.out.println("使用replaceAll方法替换元素");
		System.out.println("未替换");
		System.out.println(list);
		Collections.replaceAll(list, "abc", "wahaha");
		System.out.println("替换后。。。");
		System.out.println(list);
	}
	public static void demo6(List<String> list){
		//使用默认随机源随机更改指定列表的序列。所有序列更改发生的可能性都是大致相等的。
		System.out.println("使用shuffle更改指定列表的序列");
		System.out.println("更改前");
		System.out.println(list);
		Collections.shuffle(list);
		System.out.println("更改后。。。");
		System.out.println(list);
	}
}
result:

示例:

package com.leaf.test;

import java.util.ArrayList;
import java.util.List;

public class CollectionsDemo5 {
	/**
	 * 给非同步的集合加锁
	 * @param args
	 */
	public static void main(String[] args) {
		//非同步的集合
		List list = new ArrayList();
		//加上锁,变成同步的
		list = new MyCollections().synList(list);
	}

}
class MyCollections{
	public List synList(List list){
		return new MyList(list);
	}
	private class MyList extends ArrayList{
		private List list;
		private final Object lock = new Object();
		MyList(List list){
			this.list = list;
		}
		public boolean add(Object obj){
			synchronized(lock){
				return list.add(obj);
			}
		}
		public boolean remove(Object obj){
			synchronized(lock){
				return list.remove(obj);
			}
			
		}
	}
}

三、Arrays工具类

数组的工具类,里面的存放的都是操作数组的静态方法

示例:

package com.leaf.test;

import java.util.Arrays;

public class ArraysDemo {

	public static void main(String[] args) {
		int[] arr = { 10, 5, 6, 8, 2, 9, 2, 3, 4, 5 };
		//打印出数组
		System.out.println("-----------打印出数组------------");
		System.out.println(Arrays.toString(arr));
		//对数组进行排序
		System.out.println("-----------数组排序------------");
		Arrays.sort(arr);
		System.out.println(Arrays.toString(arr));
	}

}

result:

重点:

List asList(数组)将数组转成集合

好处:

可以使用集合的方法操作数组

弊端:

因为数组的长度是有限的,所以集合的增删操作是不可用的,否则会发送UnsupportedOperationException。

示例:

package com.leaf.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ArraysDemo2 {

	public static void main(String[] args) {
		String[] arr = {"abc","qwe","zxc"};
		List<String> list = new ArrayList<String>();
		System.out.println(list);
		list = Arrays.asList(arr);
		System.out.println(list);
		System.out.println(list.contains("abc"));
	}

}

result:


示例:由于集合中不能存储基本数据类型,所以当数组中的元素是基本数据类型的时候,那么数据就变成对象存入集合,如果数组中的元素是对象,则是对象变成集合中的元素

package com.leaf.test;

import java.util.Arrays;
import java.util.List;

class ArraysDemo4 {
	public static void main(String[] args) {
		int[] arr1 = { 3, 1, 5, 6 };
		List list1 = Arrays.asList(arr1);
		System.out.println(list1);

		Integer[] arr2 = { 3, 1, 5, 6 };
		List list2 = Arrays.asList(arr2);
		System.out.println(list2);
	}
}
result:

集合转数组:

使用的是Collection接口中的toArray方法

注:集合转成数组,可以对集合中的元素操作的方法进行限定,不允许对其进行增删

toArray方法需要传入一个指定类型的数组

长度该如何定义?

使用集合的size方法得到集合的长度,进行定义数组。

示例:

package com.leaf.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ColToArray {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("abc1");
		list.add("abc2");
		list.add("abc3");

		String[] arr = list.toArray(new String[2]);

		System.out.println(Arrays.toString(arr));
	}
}
result:








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值