黑马程序员——集合框架类学习

来源:互联网 发布:软件开发专业就业方向 编辑:程序博客网 时间:2024/06/16 05:02

------- android培训、java培训、期待与您交流! ----------

一、Collection接口,该接口提供了一些对集合类对象的基本操作方法,下面有两个主要的子类——List和Set集合类。List和Set的相同点是都实现了Collection接口,都有一些共性的基本操作方法。区别是List集合类保存的元素是有序的(即存的顺序和取出的顺序一致),元素是可以重复的,而且带有索引。Set集合类则是无序的、元素不可重复,没有索引。

1、List类的常用子类——ArrayList、LinkedList和Vector,由于ArrayList最常用,故以ArrayList说明问题,为了在编程过程中保存类型安全,需要在使用集合类的时候指定接收类型(即泛型问题)。ArrayList底层是通过数组来实现的,故它存在索引访问方式,同时还可以通过通用的迭代器来遍历集合类的元素。它的特点是:通过索引访问元素效率比较高,然而,在增加和删除元素时,由于处理位置后面的元素需要进行移位操作,索引使得在增删操作时效率不高。eg:

class ArrayTest{public static void main(String[] args){ArrayList<String> arrList=new ArrayList<String>();//注意在指定接收类型的时候,要用引用对象类型,不能使用基本数据类型,例如要存int类型元素,指定类型就为其封装类IntegerarrList.add("tianjin");//添加元素arrList.add("shanghai");arrList.add("beijing");arrList.add(1,"wuhan");//在指定位置添加元素arrList.set(2,"hangzhou");//修改指定位置的元素信息//集合类的遍历,第一种通过索引for(int i=0;i<arrList.size();i++){System.out.println("遍历元素"+i+":"+arrList.get(i));}//第二种遍历方式,通过Iterator迭代器实现int index=0;Iterator<String> iter=arrList.iterator();//调用iterator方法返回一个迭代器while(iter.hasNext())//通过Iterator的hasNext方法判断元素是否存在{System.out.println("遍历元素"+index+":"+iter.next());index++;}}}


当然,也可以保存自定义的复杂结构的数据,整个操作过程大致是一样的。注意:在使用Iterator迭代器遍历元素过程中对元素进行添加、删除等操作是不可以的,会报ConcurrentModificationException异常,这是由于你在删除元素的时候,集合类和迭代器同时操作元素,在迭代器中进行引用元素的删除操作,迭代器自身并不知道,故产生了该异常。

问题解决:可以通过Iterator下的一个子类对象ListIterator来操作,因为在该类下有一些对元素进行增删改查操作的基本方法,而通过List的listIterator方法正好可以返回一个ListIterator对象,进而可以对集合类元素进行操作。

二、Set集合类的应用:有两个常用集合HashSet和TreeSet。由其名字就可以知道HashSet底层是通过哈希表来实现的,故是无序保存且是保证元素唯一的;而TreeSet底层是通过二叉树数据结构来实现的,可以对其内部元素进行自然排序,不可有重复元素。

1、首先,HashSet是通过哈希表来保存元素的,哈希表中是按照哈希值进行排序,而要保证元素的唯一性就是通过元素的hashCode和equals方法共同完成的。保证元素唯一的原理是:对存进来的元素首先判断其hashCode的返回值是否相同,如果不同说明元素唯一,则存入集合中;如果哈希值相同则会通过调用元素自身的equals方法来判断元素值是否相同(通过equals的返回值,0表示元素值相同),相同则不予存储。

所以,要想往Set集合类中存入自定义对象元素,在创建自定义对象的时候就要复写hashCode和equals方法,保证对象能够正确地存入HashSet中。

import java.util.*;class HashSetDemo {public static void main(String[] args) {/*HashSet<String> hSet=new HashSet<String>();hSet.add("beijing");hSet.add("tianjin");hSet.add("hangzhou");hSet.add("shanghai");hSet.add("shengzhen");//添加两个重复的元素hSet.add("beijing");hSet.add("tianjin");System.out.println(hSet);//打印数据可以看出元素是无序的,但是,//beijing和tianjing两个重复的元素没有保存下来,说明,Set集合保证了元素唯一//其原理:主要是调用了String类中的hashCode和equals方法,所以在创建自定义类的时候,//有必要对这两个方法进行复写,否则在存入Set集合时无法保证元素唯一*///创建一个用于保存Person元素的Set集合类对象HashSet<Person> hash=new HashSet<Person>();hash.add(new Person("gao1","1234"));hash.add(new Person("guo","1354"));hash.add(new Person("zhang","1432"));hash.add(new Person("wang","1634"));hash.add(new Person("gao1","1623"));hash.add(new Person("gao","1234"));//System.out.println(hash);//输出元素数据Iterator<Person> iter=hash.iterator();while(iter.hasNext()){Person p=iter.next();System.out.println("PersonName:"+p.getName()+"   "+"PersonId:"+p.getId());}//}}//创建一个Person类,有姓名和身份证号两个属性,//靠身份证号来确定Person对象的唯一性class Person{private String name;//姓名private String id;//身份证号public Person(String name,String id){this.name=name;this.id=id;}public void setName(String name){this.name=name;}public void setId(String id){this.id=id;}public String getName(){return name;}public String getId(){return id;}//注意为了让该类的对象能够作为元素存入到Set集合类中,需要复写两个方法public int hashCode(){return this.id.hashCode();//身份证号唯一确定哈希码(不能用重复的身份证号)}public boolean equals(Object obj){if(!(obj instanceof Person))throw new RuntimeException("比较类型不匹配!");Person p=(Person)obj;return this.id.equals(p.getId());}}

输出结果:

在使用该集合类的时候最重要的一点就是,要根据该集合类保证成员唯一性的特点,在你存储数据的类型中要根据需求复写hashCode和equals方法。

2、Set集合类中的另一个常用的子类是TreeSet,该类的底层是通过二叉树结构来实现的,即有个参考根节点,然后比根节点大的存到右子树,小的存到左子树。所以,该集合类的特点就是可以对里面的元素排序,排序的原理是通过一个比较器或者实现接口Comparable中的comapreTo方法实现(根据其返回值-正数、负数、0(表示重复元素不予保存))。

实现比较的两种方式:1、通过复写接口Comparable的compareTo方法,实现自定义排序。2、通过自行设计一个继承自Coparator的子类,复写compare(s1,s2)的方法,然后在应用时创建一个比较器(自己设计的类)引用对象,然后将其作为参数传递给TreeSet的构造函数即可。

<pre name="code" class="java">import java.util.*;class HashSetDemo1 {public static void main(String[] args) {/*HashSet<Person> hash=new HashSet<Person>();hash.add(new Person("gao1","1234"));hash.add(new Person("guo","1354"));hash.add(new Person("zhang","1432"));hash.add(new Person("wang","1634"));hash.add(new Person("gao1","1623"));hash.add(new Person("gao","1234"));Iterator<Person> iter=hash.iterator();while(iter.hasNext()){Person p=iter.next();System.out.println("PersonName:"+p.getName()+"   "+"PersonId:"+p.getId());}*///利用TreeSet集合类保存Person对象元素TreeSet<Person> tree=new TreeSet<Person>(new NewComparator());//第二种方式——传入一个自定义比较器的引用,该方式具有较高优先级tree.add(new Person("gao1","1234"));tree.add(new Person("guo","1354"));tree.add(new Person("zhang","1432"));tree.add(new Person("wang","1634"));tree.add(new Person("gao1","1623"));tree.add(new Person("gao","1234"));//System.out.println(hash);//输出元素数据Iterator<Person> iter=tree.iterator();while(iter.hasNext()){Person p=iter.next();System.out.println("PersonName:"+p.getName()+"   "+"PersonId:"+p.getId());}//}}//创建一个Person类,有姓名和身份证号两个属性,//靠身份证号来确定Person对象的唯一性class Person implements Comparable<Person>{private String name;//姓名private String id;//身份证号public Person(String name,String id){this.name=name;this.id=id;}public void setName(String name){this.name=name;}public void setId(String id){this.id=id;}public String getName(){return name;}public String getId(){return id;}//注意为了让该类的对象能够作为元素存入到Set集合类中,需要复写两个方法public int hashCode(){return this.id.hashCode();//身份证号唯一确定哈希码(不能用重复的身份证号)}public boolean equals(Object obj){if(!(obj instanceof Person))throw new RuntimeException("比较类型不匹配!");Person p=(Person)obj;return this.id.equals(p.getId());}//为适应TreeSet集合类的存储,需要实现接口Comparable,复写compareTo方法——第一种控制排序的方式public int compareTo(Person p){//按姓名排序int num=this.name.compareTo(p.getName());if(0==num)return this.id.compareTo(p.getId());return num;}}//第二种控制比较排序的方式,创建Comparator的子类class NewComparator implements Comparator<Person>{public int compare(Person p1,Person p2){//按照身份证号的顺序排序return p1.getId().compareTo(p2.getId());}}


运行结果:

三、Map集合类:Map和Collection的最大的不同就是:Collection是单列存储元素——即元素值,而Map存储双列元素——实际保存的是<Key,Value>的键值对组合。常用的两个子类是HashMap和TreeMap,他们的底层实现结构同HashSet和TreeSet一样,分别是哈希表和二叉树。该集合类也提供了对集合进行操作的基本方法如添加put(k,v),删除remove(k),判断cotainsKey(k)、containsValue(v)、isEmpty(),获取get(k)。

注意:Map集合类无法直接遍历自身的元素,而是要通过返回Set集合对象的方式,然后通过Set结合的迭代器方式去遍历Map自身的元素信息。这里有两个重要方法:Set<Key> keySet()和Set<Map.Entry<Key,Value>> entrySet(),他们返回的都是一个Set集合对象,但是这两个集合对象里的元素是不同的:第一个保存的是Key,而第二个保存的是Key和Value的映射关系——Map.Entry<Key,Value>。具体操作见实例:

import java.util.*;//将Person类的对象与其对于的电话号码作为一组键值对,保存到TreeMap中,其中Person对象为Key,电话号码为Valueclass TreeMapDemo {public static void main(String[] args) {//利用TreeMap集合类保存Person对象和电话号码键值对元素TreeMap<Person,String> tree=new TreeMap<Person,String>();tree.put(new Person("gao1","1234"),"13523452");tree.put(new Person("guo","1354"),"132243452");tree.put(new Person("zhang","1432"),"138267842");tree.put(new Person("wang","1634"),"18723494");tree.put(new Person("gao1","1623"),"15224252");tree.put(new Person("gao","1234"),"1513523452");//System.out.println(hash);//通过keySet方法返回保存Key的Set集合,通过操作Set集合的Iterator对象来遍历Map中的元素System.out.println("第一种遍历方式的结果:");Set<Person> set=tree.keySet();Iterator<Person> iter=set.iterator();while(iter.hasNext()){Person p=iter.next();System.out.println("PersonName:"+p.getName()+"   "+"PersonId:"+p.getId()+"--电话号码:"+tree.get(p));}//通过entrySet方式遍历System.out.println("第二种遍历方式的结果:");Set<Map.Entry<Person,String>> entrySet=tree.entrySet();Iterator<Map.Entry<Person,String>> entryIter=entrySet.iterator();while(entryIter.hasNext()){Map.Entry<Person,String> entry=entryIter.next();Person p=entry.getKey();System.out.println("PersonName:"+p.getName()+"   "+"PersonId:"+p.getId()+"--电话号码:"+entry.getValue());}}}//创建一个Person类,有姓名和身份证号两个属性,//靠身份证号来确定Person对象的唯一性class Person implements Comparable<Person>{private String name;//姓名private String id;//身份证号public Person(String name,String id){this.name=name;this.id=id;}public void setName(String name){this.name=name;}public void setId(String id){this.id=id;}public String getName(){return name;}public String getId(){return id;}//注意为了让该类的对象能够作为元素存入到Set集合类中,需要复写两个方法public int hashCode(){return this.id.hashCode();//身份证号唯一确定哈希码(不能用重复的身份证号)}public boolean equals(Object obj){if(!(obj instanceof Person))throw new RuntimeException("比较类型不匹配!");Person p=(Person)obj;return this.id.equals(p.getId());}//为适应TreeSet集合类的存储,需要实现接口Comparable,复写compareTo方法——第一种控制排序的方式public int compareTo(Person p){//按姓名排序int num=this.name.compareTo(p.getName());if(0==num)return this.id.compareTo(p.getId());return num;}}//第二种控制比较排序的方式,创建Comparator的子类class NewComparator implements Comparator<Person>{public int compare(Person p1,Person p2){//按照身份证号的顺序排序return p1.getId().compareTo(p2.getId());}}

运作结果:


总结:对于哈希表结构实现的集合类,在自定义元素类型的时候,切记要根据需求复写两个方法——hashCode和equals;对于二叉树结构实现的集合类,在自定义元素类型是要实现接口Comparable的compareTo方法或者自定义比较器实现接口Comparator,复写compare方法,然后将其引用作为参数传递给Tree集合类的构造函数。

0 0
原创粉丝点击