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

来源:互联网 发布:天刀捏脸数据库男性萌 编辑:程序博客网 时间:2024/05/16 03:49

------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:








0 0