黑马程序员-java集合类总结

来源:互联网 发布:java cst时间转换 编辑:程序博客网 时间:2024/06/05 23:02

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------


一、集合类概述

1、为什么出现集合类

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储。集合就是存储对象最常用的一种方式。

2、数组和集合类同是容器,两者有何区别

数组虽然也可以存储对象,但其长度是固定的,数组中可以存储基本数据类型;集合长度是可变的,集合只能存储对象。

3、集合类的特点

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

4、集合类的关系图


1)java集合的框架大致可分为两大类,一类是Collection,另一类是Map。Collection接口实现了Iterator接口,即迭代器接口,这意味着Collection接口的实现类可以调用Iterator接口的方法实现迭代器行为。Collection和Map的不同之处在于,Collection类集合存储单个对象,而Map类集合存储两个对象的键值对。

2)java提供了Collections、Arrays两个工具类,提供诸如集合排序、数组和集合的互换等功能。

3)Collection接口下又分为List接口与Set接口。List接口的主要实现类为ArrayList、LinkedList、Vector;Set接口的主要实现类为HashSet、TreeSet、LinkedHashSet。


二、Collection

1、常见操作

因为Collection为接口,不能建立对象,我们以ArrayList为例,

例1:

import java.util.*;class Test {public static void main(String[] args) {ArrayList al=new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");//打印集合System.out.println("原集合:"+al);//判断元素System.out.println("java03是否存在:"+al.contains("java03"));System.out.println("集合是否为空:"+al.isEmpty());//获取个数,即集合长度System.out.println("Size="+al.size());//删除元素al.remove("java02");System.out.println("删除后集合:"+al);//清空集合al.clear();System.out.println("清空后集合:"+al);}}

输出结果:

原集合:[java01, java02, java03]java03是否存在:true集合是否为空:falseSize=3删除后集合:[java01, java03]清空后集合:[]

2、迭代器

什么是迭代器呢?其实就是集合取出元素的方式。

例2:

import java.util.*;class Test {public static void main(String[] args) {ArrayList al=new ArrayList();al.add("AAA");al.add("BBB");al.add("CCC");//获取迭代器Iterator it=al.iterator();while (it.hasNext()){System.out.println(it.next());}}}

输出结果:

AAABBBCCC


三、List

元素是有序的,元素可以重复。因为该集合体系有索引。

1、List特有方法:凡是可以操作角标的方法都是该体系特有的方法。

例3:

import java.util.*;class Test {public static void main(String[] args) {ArrayList al=new ArrayList(); //添加元素al.add("java001");al.add("java002");al.add("java003");al.add("java004");al.add("java005");//List特有方法//在指定位置添加元素al.add(1,"java");//删除指定位置元素al.remove(2);//修改元素al.set(2,"java007");//通过角标获取元素for (int x=0;x<al.size() ;x++ ){System.out.println("al("+x+")="+al.get(x));}}}
输出结果:

al(0)=java001al(1)=javaal(2)=java007al(3)=java004al(4)=java005

2、List特有的迭代器:ListIterator

在迭代时,不可以通过集合对象的方法操作集合中的元素,否则会发生ConcurrentModificationException(并发修改异常)。所以,在迭代时,只能用迭代器的方法操作元素。然而,Iterator提供的方法十分有限,只能对元素进行判断、取出及删除的操作。如果想要进行其他的操作,如添加、修改等,就需要使用其子接口:ListIterator。

该接口只能通过List集合的listIterator()方法获取。

例4:

import java.util.*;class Test {public static void main(String[] args) {ArrayList al=new ArrayList(); //添加元素al.add("java001");al.add("java002");al.add("java003");al.add("java004");al.add("java005");//并发修改异常/*Iterator it=al.iterator();while(it.hasNext()){Object obj=it.next();if(obj.equals("java002"))al.add("java007");    //错误,并发修改异常}*///利用ListIterator在迭代过程中,添加\修改\删除元素ListIterator lit=al.listIterator();while (lit.hasNext()){Object obj=lit.next();if(obj.equals("java002"))lit.add("java008");    //正确,不会发生并发修改异常System.out.println("obj="+obj);}System.out.println(al);}}

输出结果:

obj=java001obj=java002obj=java003obj=java004obj=java005[java001, java002, java008, java003, java004, java005]


3、List集合各实现类的特点

Collection

|--List:元素是有序的,元素可以重复,因为该集合体系有索引。

|--ArrayList:底层使用数组数据结构。特点:查询速度很快,但是增删稍慢。线程不同步。

|--LinkedList:底层使用链表数据结构。特点:增删速度很快,查询稍慢。

|--Vector:底层使用数组数据结构。特点:线程同步,被ArrayList替代了。

1)ArrayList:

基于数组实现的,可以理解为可变数组,允许null元素,集合内部的元素顺序排列。

2)LinkedList:

基于双向链表实现的,允许null元素。通过提供特有的offerFirst()、peekFirst()、pollFirst()等方法,使LinkedList可用于模拟堆栈(stack)、队列(queue)或双向队列(deque)数据结构。

例5:使用LinkedList模拟一个队列数据结构。队列:先进先出

class DuiLie{private LinkedList ll;DuiLie(){ll=new LinkedList();}public void add(Object obj){ll.addFirst(obj);}public Object get(){return ll.removeLast();}public boolean isEmpty(){return ll.isEmpty();}public int size(){return ll.size();}public void sop(){for (int x=0;x<ll.size() ;x++ ){System.out.println(ll.get(x));}}}

延伸阅读:请参阅When to use LinkedList<> over ArrayList<>?来了解,两种集合的使用场合。

3)Vector

Vector非常类似ArrayList,两者的主要区别在于,Vector是同步的,而ArrayList不同步。因此,在性能上Vector稍差于ArrayList。

4、List集合判断元素是否相同的依据

List集合根据元素的equals()来判断元素是否相同。contains()、remove()等方法在判断集合中的元素是否为目标元素时,也是调用equals()方法。

例6:

import java.util.*;class Test {public static void main(String[] args) {//去除重复学生案例ArrayList al=new ArrayList();al.add(new Student("A",1));al.add(new Student("A",1));al.add(new Student("B",1));al.add(new Student("B",1));al.add(new Student("B",1));al.add(new Student("B",2));al.add(new Student("C",3));al.add(new Student("C",3));System.out.println("old:"+al);al=SingleElement(al);System.out.println("new:"+al);}//去除重复元素。此例证明,List集合通过equals()方法判断元素是否相同。//即,contains(),remove()方法,底层调用的都是equals()方法;public static ArrayList SingleElement(ArrayList al){ArrayList newAl=new ArrayList();Iterator it=al.iterator();while (it.hasNext()){Object obj=it.next();if(!newAl.contains(obj))newAl.add(obj);}return newAl;}}class Student{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}//复写equals方法,学生的名字和年龄都相同时才认为两者相同public boolean equals(Object obj){if (!(obj instanceof Student))return false;Student st=(Student)obj;return (this.name.equals(st.name))&&(this.age==st.age);}public String toString(){return "("+this.name+","+this.age+")";}}

输出结果:

old:[(A,1), (A,1), (B,1), (B,1), (B,1), (B,2), (C,3), (C,3)]new:[(A,1), (B,1), (B,2), (C,3)]

四、Set

Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。

|--HashSet:底层使用哈希表数据结构。线程是非同步的

|--TreeSet:底层使用二叉树数据结构。可以对元素进行排序。

1、HashSet:

底层使用哈希表数据结构。线程是非同步的。

保证元素唯一性原理:判断元素的hashCode值是否相同,若相同,则继续通过equals方法判断元素是否相同。

两个元素相同,则它们的hashCode值一定相同,但若两个元素不相同,则它们的hashCode值不一定不相同。

例7:

import java.util.*;class Test {public static void main(String[] args) {/*去除重复学生案例2/*此例证明,HashSet集合通过hashCode()、equals()方法判断元素是否相同。/*即,contains(),remove()方法,底层调用的都是这两个方法;/******************************************************************/HashSet hs=new HashSet();hs.add(new Student("A",1));hs.add(new Student("A",1));hs.add(new Student("B",1));hs.add(new Student("B",1));hs.add(new Student("B",1));hs.add(new Student("B",2));hs.add(new Student("C",3));hs.add(new Student("C",3));System.out.println("Set:"+hs);}}class Student{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}//复写equals方法,学生的名字和年龄都相同时才认为两者相同public boolean equals(Object obj){if (!(obj instanceof Student))return false;Student st=(Student)obj;return (this.name.equals(st.name))&&(this.age==st.age);}//复写hashCode方法public int hashCode(){return name.hashCode()+age*37;}public String toString(){return "("+this.name+","+this.age+")";}}

输出结果:

Set:[(A,1), (B,1), (B,2), (C,3)]

2、TreeSet

底层使用二叉树数据结构。可以对元素进行排序。

保证元素唯一性的原理:compareTo()方法返回0,则认为两个元素相同。

TreeSet有两种排序方式:

1)元素自身具有比较性

方法:让元素所属的类继承Comparable接口,并重写compareTo()方法,则元素自身就具有了比较性。这种方式也称为元素的自然顺序。

例8:

import java.util.*;class Test {public static void main(String[] args) {TreeSet ts=new TreeSet();ts.add(new Student("asd",20));ts.add(new Student("aasdfd",10));ts.add(new Student("gedd",22));ts.add(new Student("re",23));ts.add(new Student("2013d",12));ts.add(new Student("x",9));System.out.println("排序后");    //即添加元素时,集合自动排序Iterator it=ts.iterator();while (it.hasNext()){Student s=(Student)it.next();System.out.println(s.getName()+"..."+s.getAge());}}}//TreeSet第一种排序法,让元素具有比较性class Student implements Comparable{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}//复写compareTo方法,以学生的年龄为主要条件,姓名为次要条件,升序排序public int compareTo(Object obj){if(!(obj instanceof Student))throw new RuntimeException();Student s=(Student)obj;System.out.println(s.name+"..."+s.age);int num=new Integer(this.age).compareTo(new Integer(s.age));if(num==0)return this.name.compareTo(s.name);return num;}public String toString(){return name+"@"+age;}public String getName(){return name;}public int getAge(){return age;}}

输出结果:

asd...20asd...20asd...20asd...20gedd...22asd...20aasdfd...10asd...20aasdfd...10排序后x...9aasdfd...102013d...12asd...20gedd...22re...23

由结果可知,1)TreeSet在添加元素时,会利用compareTo方法依次与集合中已有的元素进行比较;2)根据compareTo方法的返回值判断两个元素的先后顺序,从而完成排序。

2)让集合自身具有比较性

当元素自身不具有比较性,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性。

方法:自定义一个比较器类继承Comparator接口,重写compare()方法。

例9:

import java.util.*;class Test {public static void main(String[] args) {TreeSet ts=new TreeSet(new MyComparator());//构造TreeSet时,传入自定义比较器ts.add(new Student("asd",20));ts.add(new Student("aasdfd",10));ts.add(new Student("gedd",22));ts.add(new Student("re",23));ts.add(new Student("2013d",12));ts.add(new Student("x",9));System.out.println("排序后");    //即添加元素时,集合自动排序Iterator it=ts.iterator();while (it.hasNext()){Student s=(Student)it.next();System.out.println(s.getName()+"..."+s.getAge());}}}//TreeSet第一种排序法,让元素具有比较性class Student implements Comparable{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}//复写compareTo方法,以学生的年龄为主要条件,姓名为次要条件,升序排序public int compareTo(Object obj){if(!(obj instanceof Student))throw new RuntimeException();Student s=(Student)obj;System.out.println(s.name+"..."+s.age);int num=new Integer(this.age).compareTo(new Integer(s.age));if(num==0)return this.name.compareTo(s.name);return num;}public String toString(){return name+"@"+age;}public String getName(){return name;}public int getAge(){return age;}}//TreeSet第二种排序方法,让集合具有比较性class MyComparator implements Comparator{//重写compare方法,以学生名字的长度为主要条件,学生的年龄为次要添加,升序排序public int compare(Object o1,Object o2){Student s1=(Student)o1;Student s2=(Student)o2;int num=new Integer(s1.getName().length()).compareTo(new Integer(s2.getName().length()));if(num==0)return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));return num;}}

输出结果:

排序后x...9re...23asd...20gedd...222013d...12aasdfd...10
由结果可知,TreeSet采用第二种排序方式时,是根据比较器中的compare()方法来对元素进行比较排序的。


五、Map

Map:该集合存储键值对,而且键值不可重复。

|--HashTable:底层是哈希表数据结构,不可以存入null键和null值。该集合是线程同步的,效率低。

|--HashMap:底层是哈希表数据结构,允许存入null键和null值。该集合是不同步的,效率高。

|--TreeMap:底层是二叉树数据结构。线程不同步。可以给集合中的键进行排序。

Map和Set很像,其实Set的底层就是使用Map实现的。

1、基本功能

例10:

import java.util.*;class Test {public static void main(String[] args) {//基本功能HashMap<String,String> hm=new HashMap<String,String>();//添加元素。如果添加时,键相同,则该键对应的值会覆盖原有键对应的值,并返回原来的值System.out.println(hm.put("01","A"));System.out.println(hm.put("01","D"));hm.put("02","B");hm.put("03","C");System.out.println(hm.containsKey("01"));//判断是否包含某键System.out.println(hm.get("01"));        //通过键查找对应的值Collection<String> coll=hm.values();     //获得Map集合中所有的值System.out.println(coll);System.out.println(hm);}}

输出结果:

nullAtrueD[D, B, C]{01=D, 02=B, 03=C}
2、取出元素方式

Map集合提供两种取出方式:

1)Set<K> keySet():将Map中所有的键存入到一个Set集合。Set集合具备迭代器,可以通过迭代方式取出所有的键,然后再用get()方法获取每一个键对应的值。

2)Set<Map.Entry<K,V>> entrySet():将Map中的所有映射关系存入到一个Set集合中,而这个映射关系的数据类型就是:Map.Entry
例11:

import java.util.*;class Test {public static void main(String[] args) {//学生案例TreeMap<Student,String> hm=new TreeMap<Student,String>(new StuNameComparator());hm.put(new Student("AAA",20),"BeiJing");hm.put(new Student("B",22),"HangZhou");hm.put(new Student("CC",23),"ChengDu");//第一种取出方式Set<Student> ks=hm.keySet();        //先获取Map集合的所有键的Set集合:keySet()Iterator<Student> it=ks.iterator(); //获取迭代器while (it.hasNext()){Student s=it.next();String add=hm.get(s);       //有了键,通过Map集合的get()方法获取其对应的值System.out.println(s+"..."+add);}//第二种取出方式Set<Map.Entry<Student,String>> es=hm.entrySet();   //将Map集合中的映射关系存入到Set集合中,entrySet()Iterator<Map.Entry<Student,String>> it2=es.iterator();while (it2.hasNext()){Map.Entry<Student,String> me=it2.next();Student s=me.getKey();                     //Map.Entry特有的获取键的方法String str=me.getValue();                  //Map.Entry特有的获取值的方法System.out.println(s+"///"+str);}}}class Student implements Comparable<Student>{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}public String getName(){return name;}public int getAge(){return age;}public boolean equals(Object obj){if(!(obj instanceof Student))throw new RuntimeException();Student s=(Student)obj;return this.name.equals(s.name)&&this.age==s.age;}public int hashCode(){return name.hashCode()+10*age;}public int compareTo(Student s){int num=this.name.compareTo(s.name);if(num==0)return new Integer(this.age).compareTo(new Integer(s.age));return num;}public String toString(){return name+"@"+age;}}class StuNameComparator implements Comparator<Student>{public int compare(Student s1,Student s2){int num=new Integer(s1.getName().length()).compareTo(new Integer(s2.getName().length()));if(num==0)return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));return num;}}

输出结果:

B@22...HangZhouCC@23...ChengDuAAA@20...BeiJingB@22///HangZhouCC@23///ChengDuAAA@20///BeiJing

六、Collections与Arrays工具类

1、Collections

对Collection类集合进行操作的工具类。

常见方法:

static <T extends Comparable<? super T>> void sort(List<T> list) //对List进行排序static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)  //根据比较器的排序,返回集合中的最大元素static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) //以二分法的形式,在List集合中查找某元素static <T> void fill(List<? super T> list, T obj)  //将集合中的元素全部替换成指定元素

例12:

import java.util.*;class  CollectionsTest{public static void main(String[] args) {ArrayList<String> list=new ArrayList<String>();list.add("fcg");list.add("defd");list.add("aa");list.add("aaa");list.add("d");//sort()System.out.println("排序前:"+list);Collections.sort(list,new StrLenComparator());System.out.println("排序后:"+list);//反转Collections.reverse(list);System.out.println("reverse后:"+list);//max()System.out.println("默认max:"+Collections.max(list));System.out.println("根据比较器的max:"+Collections.max(list,new StrLenComparator()));//binarySearch()System.out.println("aaa在第"+Collections.binarySearch(list,"aaa")+"个");//fill(),全部替换Collections.fill(list,"aa");System.out.println("fill后:"+list);//replaceAllCollections.replaceAll(list,"aa","bb");System.out.println("replaceAll后:"+list);}}class StrLenComparator implements Comparator<String>{public int compare(String str1,String str2){int num=new Integer(str1.length()).compareTo(new Integer(str2.length()));if(num==0)return str1.compareTo(str2);return num;}}

输出结果:

排序前:[fcg, defd, aa, aaa, d]排序后:[d, aa, aaa, fcg, defd]reverse后:[defd, fcg, aaa, aa, d]默认max:fcg根据比较器的max:defdaaa在第2个fill后:[aa, aa, aa, aa, aa]replaceAll后:[bb, bb, bb, bb, bb]


延伸阅读:

关于 Java Collections API 您不知道的 5 件事,第 1 部分与关于 Java Collections API 您不知道的 5 件事,第 2 部分

2、Arrays

用于操作数组的工具类。

我们只介绍其中一个:

数组变集合:

static <T> List<T> asList(T... a) //将数组转成集合
将数组转成List集合后,可以使用集合的思想和方法操作数组中的元素,但不可以使用集合的增删方法。因为数组的长度是固定的。


集合变数组:

Collection中的方法:

public <T> T[] toArray(T[] a) //将集合转成数组
将集合转成数组后,就限定了对元素的操作,不能再进行增删操作了。
例13:

import java.util.*;class  CollectionsTest{public static void main(String[] args) {//数组变集合String[] arr={"a","bb","ccc"};List<String> list=Arrays.asList(arr);//list.add("dddd");//错误,不能使用集合的增删功能ArrayList<String> newList=new ArrayList<String>(Arrays.asList(arr));newList.add("dddd");//OK!System.out.println(list);//数组变集合2int[] num={1,2,3};System.out.println(Arrays.asList(num));//数组元素必须为对象,否则只将该数组作为集合中的元素存在Integer[] num2={1,2,3};System.out.println(Arrays.asList(num2));//这样就没问题了//集合变数组String[] arr1=list.toArray(new String[list.size()]);for (String str:arr1){System.out.print(str+" ");}}}

输出结果:

[a, bb, ccc][[I@188edd79][1, 2, 3]a bb ccc 

延伸阅读:

欲深入了解ArrayList、HashMap、HashSet等的实现原理,请参考

深入Java集合学习系列:ArrayList的实现原理等系列。


---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com

0 0
原创粉丝点击