黑马程序员-Collection集合
2015-10-18 00:48
459 查看
——- android培训、java培训、期待与您交流! ———-
2)不同点:集合长度是可变,数组长度是指定的;集合可以装不同类型的对象,数组只可以装同一类型的对象。
集合是可以存储Object类型的任意对象,而数组一般用来装基本数据类型的容器。
Collection有两个常用子类
(1)List:存放有序对象(存入和输出顺序一致),可以有重复元素(通过索引区别)
(2)Set:无序(输出顺序不止一种,对象随机输出),不可存入重复元素。
List有三个常用子类
|——-ArrayList:底层为数组结构,有下标,查询速度快,但是增加/删除的速度慢。线程不同步,效率高,可变数组长度,默认为10个长度,超过长度时,按50%增长,不浪费空间。
|——-LinkedList:底层为链表结构,手拉手,查询速度慢,但是增删速度快。
|——-Vector:底层为数组结构,线程同步,效率低,被ArrayList取代。可变数组长度,默认为10,超过时按100%增长,浪费空间。
Set有两个常用子类
|——-HashSet:数据存储结构为哈希表,哈希值是系统随机分配的,也可以自定义覆写hashCode方法。判断元素是否重复,需要两步,第一步判断哈希值是否相等,第二步判断equals是否相等。如果下元素的hashCode相等,才会判断equals是否相等,如果元素的hashCode不相等,则不会调用equals方法。
|——-TreeSet:可以对容器中的对象进行自动排序。自定义对象需要实现Comparable接口,强制实现排序,但是需要覆写compareTo方法,具备了自然顺序。
1)add(Object obj),第一点:加入的对象为Object类型,任意类型的。第二点:存入的对象为obj对象的地址,即引用,而不是对象本身。
2)remove(obj),删除某个对象
3)clear(),清空
4)size()集合长度,大小
5)isEmpty()集合是否为空
6)retainAll()取两个集合的交集。
7)迭代器取出集合中的各个元素
或者下面方法,更节约系统内存。
迭代器原理:每个容器都有不同的判断和读取的方式,所以每个类中都封装了一个内部类来完成这些操作,对于不同的容器,因为都需要判断和读取这两个共性,所有抽取出来一个接口Iterator,通过iterator()方法获得内部类。
2. List类的基本方法
1)add(index element);add(index collection)
2)remove(index):删除某个位置上的元素
3) set(index element):插入操作。
4) get(index);获取第几个位置的元素
subList(from,to);截取第几个到第几个之间的集合,包含头不包含尾
listIterator()列表迭代器是List特有的:listIterator()是Iterator的子接口
5) indexOf(element)获取对象的位置
重点解析列表迭代器的作用:
当在使用迭代器输出时,如果此时使用集合修改元素,会发生并发修改异常。所以在迭代时,只能用迭代器的方法进行修改,而Iterator只有三个方法,为了获得更多的方法,使用Iterator的子接口ListIterator,从而获取更多方法,实现更多操作。
Iterator:hasNext(),next(),remove();
ListIterator : hasNext(),next()取得下一个元素;hasPrevious(),previous()取得前一个元素;set(element)修改;add(element)增加;nextIndex()返回下一个的下标;previousIndex()返回上一个元素的下标。
模拟一:堆栈,先进后出
模拟二:模拟队列,先进先出,并封装为类。在上述代码上面稍作修改即可
在主函数中测试类
示例2:去除ArrayList中的重复元素。
示例3:将自定义对象作为元素存储到ArrayList中,并去除重复元素;比如存人对象,同一姓名同一年龄视为重复元素。
首先:自定义Person类
显示结果仍然为5,因为Person类中没有覆写equals方法。
现改写Person类。
如此,就完成了需求。判断remove()和contain()都是通过equals方法进行的对象比较。
结论:对于List集合(ArrayList和LinkedList),比较集合中元素是否相等,遵循规律如下:
1)判断两个对象是否相等,在底层调用的是该方法的equals方法,
2)所有的对象如果没有覆写equals方法,则调用Object的equals方法,比的是对象的地址。
3)如果要重新定义对象相等的条件,需要重新覆写equals方法定义自己的规则。
从打印结果看出,确实没有重复元素。
如果存入自定义元素呢?
1)注释掉equals方法后,可以存入相同元素;
2)加上equals方法后,仍然可以存入相同元素;
3)加上改写的hashCode方法和equals方法后,不能存入相同元素。
总结如下:
判断元素是否重复,需要两步
第一步判断哈希值是否相等;
第二步判断equals是否相等;
如果下元素的hashCode相等,才会判断equals是否相等,如果元素的hashCode不相等,则不会调用equals方法。
TreeSet:可以对容器中的对象进行自动排序。
1)自定义对象需要实现Comparable接口,强制实现排序,但是需要覆写compareTo方法,具备了自然顺序。如果集合中元素没有实现这一接口,则会出现异常ClassCastException。
2)具有自动排序的类为String类,因为它的类里面实现了Comparable接口,并覆写了compareTo方法。
3)在排序时,当主要条件相等时,需要判断下次要条件。
4)保证元素是否相同,是通过判断compareTo方法返回值0。
示例:比较人的按年龄大小自动排序。
在给定的Person类中,按照姓名作为自动排序规则,该怎么做?
分析:需要在集合中定义比较器来实现。
定义比较器
总结如下:
(1)当元素不具备比较性,或者元素所具备的比较性不是所需要的,那么需要让容器具有比较器Comparator,覆写compare(Object obj1,Object obj2)
(2)当两种比较器都存在时,以容器的比较器为主。
示例:用TreeSet按字符串长度排序。
字符串本身具备比较规则,就是按大小排序,因此如果按字符长度排序,需要自定义比较器。
此时完成字符串按长度排序。
问题: 集合用来干什么?和数组有什么区别?
1)集合和数组都是装盛一组对象的容器。2)不同点:集合长度是可变,数组长度是指定的;集合可以装不同类型的对象,数组只可以装同一类型的对象。
集合是可以存储Object类型的任意对象,而数组一般用来装基本数据类型的容器。
(一)集合的框架
Collection是集合的最大基类。Collection有两个常用子类
(1)List:存放有序对象(存入和输出顺序一致),可以有重复元素(通过索引区别)
(2)Set:无序(输出顺序不止一种,对象随机输出),不可存入重复元素。
List有三个常用子类
|——-ArrayList:底层为数组结构,有下标,查询速度快,但是增加/删除的速度慢。线程不同步,效率高,可变数组长度,默认为10个长度,超过长度时,按50%增长,不浪费空间。
|——-LinkedList:底层为链表结构,手拉手,查询速度慢,但是增删速度快。
|——-Vector:底层为数组结构,线程同步,效率低,被ArrayList取代。可变数组长度,默认为10,超过时按100%增长,浪费空间。
Set有两个常用子类
|——-HashSet:数据存储结构为哈希表,哈希值是系统随机分配的,也可以自定义覆写hashCode方法。判断元素是否重复,需要两步,第一步判断哈希值是否相等,第二步判断equals是否相等。如果下元素的hashCode相等,才会判断equals是否相等,如果元素的hashCode不相等,则不会调用equals方法。
|——-TreeSet:可以对容器中的对象进行自动排序。自定义对象需要实现Comparable接口,强制实现排序,但是需要覆写compareTo方法,具备了自然顺序。
(二)基本方法
Collection类的基本方法:1)add(Object obj),第一点:加入的对象为Object类型,任意类型的。第二点:存入的对象为obj对象的地址,即引用,而不是对象本身。
2)remove(obj),删除某个对象
3)clear(),清空
4)size()集合长度,大小
5)isEmpty()集合是否为空
6)retainAll()取两个集合的交集。
7)迭代器取出集合中的各个元素
[code]Iterator it = list.iterator(); while(it.hasNext()) { Object obj = it.next(); }
或者下面方法,更节约系统内存。
[code]for(Iterator it = list.iterator();it.hasNext();) { Object obj = it.next(); }
迭代器原理:每个容器都有不同的判断和读取的方式,所以每个类中都封装了一个内部类来完成这些操作,对于不同的容器,因为都需要判断和读取这两个共性,所有抽取出来一个接口Iterator,通过iterator()方法获得内部类。
2. List类的基本方法
1)add(index element);add(index collection)
2)remove(index):删除某个位置上的元素
3) set(index element):插入操作。
4) get(index);获取第几个位置的元素
subList(from,to);截取第几个到第几个之间的集合,包含头不包含尾
listIterator()列表迭代器是List特有的:listIterator()是Iterator的子接口
5) indexOf(element)获取对象的位置
重点解析列表迭代器的作用:
当在使用迭代器输出时,如果此时使用集合修改元素,会发生并发修改异常。所以在迭代时,只能用迭代器的方法进行修改,而Iterator只有三个方法,为了获得更多的方法,使用Iterator的子接口ListIterator,从而获取更多方法,实现更多操作。
Iterator:hasNext(),next(),remove();
ListIterator : hasNext(),next()取得下一个元素;hasPrevious(),previous()取得前一个元素;set(element)修改;add(element)增加;nextIndex()返回下一个的下标;previousIndex()返回上一个元素的下标。
(三)List类
示例1:使用LinkedList模拟堆栈或者队列的数据结构。模拟一:堆栈,先进后出
[code]class LinkedList { public static void main(String args[]) { LinkedList ll = new LinkedList();//定义并实例化LinkedList对象 ll.addFirst("java01");//从第一个插入,依次加入元素。 ll.addFirst("java02"); ll.addFirst("java03"); ll.addFirst("java04"); while(!ll.isEmpty())//判断结束标志,当集合中还有元素时,继续打印输出。 { sop(ll.removeFirst());//从第一个开始删除,实际上删除的是最后进入的。并一一打印。 } } public static void sop(Object obj)//封装打印方法。 { System.out.println(obj); } }
模拟二:模拟队列,先进先出,并封装为类。在上述代码上面稍作修改即可
[code]class DuiLie { private LinkedList link; public DuiLie() { link = new LinkedList(); } public void myAdd(Object obj) { link.addFirst(); } public Object myGet() { link.removeLast(); } public boolean isNull() { link.isEmpty(); } }
在主函数中测试类
[code]public class TestDemo { public static void main(String args[]) { DuiLie dl = new DuiLie(); dl.myAdd("java1"); dl.myAdd("java2"); dl.myAdd("java3"); dl.myAdd("java4"); while(!dl.isNull()) { System.out.println(dl.myGet()); } } }
示例2:去除ArrayList中的重复元素。
[code]class ArrayListTest { public static void main(String args[]) { ArrayList al = new ArrayList(); al.add("java01"); al.add("java02"); al.add("java02"); al.add("java03"); al.add("java04"); al.add("java03"); sop(al); ArrayList al = changeList(al); sop(al); } public static ArrayList changeList(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; } public static void sop(Object obj) { System.out.println(obj); } }
示例3:将自定义对象作为元素存储到ArrayList中,并去除重复元素;比如存人对象,同一姓名同一年龄视为重复元素。
首先:自定义Person类
[code]class Person { private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public int getAge() { return this.age; } public String toString() { return this.name+"----"+this.age; } }
[code]class ArrayListTest { public static void main(String args[]) { ArrayList al = new ArrayList(); al.add(new Person("lisi01",25)); al.add(new Person("lisi02",24)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",22)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",24)); ArrayList al = changeList(al); sop(al); sop("lisi03"+al.remove(new Person("lisi03",23)); sop(al); } public static ArrayList changeList(ArrayList al) { ArrayList newAl = new ArrayList(); Iterator it = al.iterator(); while(it.hasNext()) { Person p = (Person)it.next(); if(!newAl.contains(p))//此处contain()方法判断对象是否相等,依据的是底层的equals方法,如果此类没有覆写equals方法,则调用的是Object中的equals方法,比较的是对象堆里面的地址。 newAl.add(obj); } return newAl; } public static void sop(Object obj) { System.out.println(obj); } }
显示结果仍然为5,因为Person类中没有覆写equals方法。
现改写Person类。
[code]class Person { private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public boolean equals(Object obj) { if(!obj.instanceof(Person)) return false; Person p = (Person)obj; return this.name.equals(p.name)&&this.age==p.name; } public String toString() { return name+"...."+age; }
如此,就完成了需求。判断remove()和contain()都是通过equals方法进行的对象比较。
结论:对于List集合(ArrayList和LinkedList),比较集合中元素是否相等,遵循规律如下:
1)判断两个对象是否相等,在底层调用的是该方法的equals方法,
2)所有的对象如果没有覆写equals方法,则调用Object的equals方法,比的是对象的地址。
3)如果要重新定义对象相等的条件,需要重新覆写equals方法定义自己的规则。
(四)Set类
HashSet:不能存入相同元素,判断的是hashCode和equals[code]class HashSetTest { public static void main(String args[]) { HashSet al = new HashSet(); al.add(new Person("lisi01",25)); al.add(new Person("lisi02",24)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",22)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",24)); sop(al.add("java08")); sop(al.add("java08")); Iterator it = al.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
从打印结果看出,确实没有重复元素。
如果存入自定义元素呢?
[code]class Person { private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } /* public boolean equals(Object obj) { if(!obj instanceof Person) return false; Person p = (Person)obj; return this.name.equals(p.name)&&this.age==p.name; } */ public String toString() { return name+"...."+age; }
1)注释掉equals方法后,可以存入相同元素;
2)加上equals方法后,仍然可以存入相同元素;
3)加上改写的hashCode方法和equals方法后,不能存入相同元素。
[code]class Person { private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public int hashCode() { return name.hashCode()+int*37; } public boolean equals(Object obj) { if(!obj instanceof Person) return false; Person p = (Person)obj; return this.name.equals(p.name)&&this.age==p.name; } public String toString() { return name+"...."+age; }
总结如下:
判断元素是否重复,需要两步
第一步判断哈希值是否相等;
第二步判断equals是否相等;
如果下元素的hashCode相等,才会判断equals是否相等,如果元素的hashCode不相等,则不会调用equals方法。
TreeSet:可以对容器中的对象进行自动排序。
1)自定义对象需要实现Comparable接口,强制实现排序,但是需要覆写compareTo方法,具备了自然顺序。如果集合中元素没有实现这一接口,则会出现异常ClassCastException。
2)具有自动排序的类为String类,因为它的类里面实现了Comparable接口,并覆写了compareTo方法。
3)在排序时,当主要条件相等时,需要判断下次要条件。
4)保证元素是否相同,是通过判断compareTo方法返回值0。
示例:比较人的按年龄大小自动排序。
[code]class Person implements Comparable { private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public int compareTo(Object obj) { if(!obj instanceof Person) return false; Person p = (Person)obj; if(this.age>p.age) return 1; if(this.age==p.age) return this.name.equals(p.name); return -1; } public String toString() { return name+"...."+age; }
[code]class TreeSetTest { public static void main(String args[]) { TreeSet al = new TreeSet(); al.add(new Person("lisi01",25)); al.add(new Person("lisi02",24)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",22)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",24)); sop(al.add(new Person("lisi05",24)); sop(al.add(new Person("lisi05",24))); Iterator it = al.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
在给定的Person类中,按照姓名作为自动排序规则,该怎么做?
分析:需要在集合中定义比较器来实现。
[code]class TreeSetTest { public static void main(String args[]) { TreeSet al = new TreeSet(new MyComparator()); al.add(new Person("lisi01",25)); al.add(new Person("lisi02",24)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",22)); al.add(new Person("lisi03",23)); al.add(new Person("lisi04",24)); sop(al.add(new Person("lisi05",24)); sop(al.add(new Person("lisi05",24))); Iterator it = al.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
定义比较器
[code]class MyComparator implements Comparator { public int compare(Object obj1,Object obj2) { Person p1 = (Person)obj1; Person p2 = (Person)obj2; int num = p1.getName().compareTo(p2.getName()); if(num==0) {//以下代码也可以用return new Integer(p1.getAge().compareTo(new Integer(p2.getAge()))); if(p1.getAge()>p2.getAge()) return 1; if(p1.getAge()==p2.getAge()) return 0; return -1; } return num; } }
总结如下:
(1)当元素不具备比较性,或者元素所具备的比较性不是所需要的,那么需要让容器具有比较器Comparator,覆写compare(Object obj1,Object obj2)
(2)当两种比较器都存在时,以容器的比较器为主。
示例:用TreeSet按字符串长度排序。
[code]public class { public static void main(String args[]) { TreeSet ts = new TreeSet(new MyComparator()); ts.add("dfds"); ts.add("ds"); ts.add("dfdsfss"); ts.add("dfs"); ts.add("dfddfsfsds"); ts.add("dfdavs"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
字符串本身具备比较规则,就是按大小排序,因此如果按字符长度排序,需要自定义比较器。
[code]class MyComparator implements Comparator { public int compare(Object obj1,Object obj2) { String s1 = (String)obj1; String s2 = (String)obj2; int num = new Integer(s1.length()).compareTo(new Integer(s2.length())); if(num==0) return s1.compareTo(s2); return num; } }
此时完成字符串按长度排序。