黑马程序员——【学习笔记】集合——集合框架及Collectiony方法

来源:互联网 发布:星际战甲优化 编辑:程序博客网 时间:2024/05/20 17:26


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


集合框架就是集合容器因为内部的数据结构不同,而不断向上抽取的系统化产物。


1 集合框架的结构


1.1 Collection接口

Collection接口是框架的顶层接口。因为Collection接口的子类并非全部都有角标(只有List子接口有,Set子接口没有),所以只有增删查三大方法,没有改(如果要改只能删除再添加,但是不能保证序列一致,或者使用有角标的List接口),但有判断。

1.1.1 增——添加

boolean add(E e):一次添加一个元素。并返回一个

boolean addAll(Collection):将一个容器中的元素添加到当前容器中。

public class Day16 {public static void main(String[] args){Collection c = new ArrayList();System.out.println(c.add(2313));System.out.println(c);System.out.println(c.add(2313));System.out.println(c);System.out.println(c.add(null));System.out.println(c);System.out.println(c.add("abcd"));System.out.println(c);System.out.println(c.add("efgh"+'a'+true));System.out.println(c);}}
true
[2313]
true
[2313, 2313]
true
[2313, 2313, null]
true
[2313, 2313, null, abcd]
true
[2313, 2313, null, abcd, efghatrue]

PS:Collection的子类ArrayList可以存放不同的数据类型(StringBuffer也可以),但不能存放基本数据类型(StringBuffer可以),上程序之所以能放2313 'a'等,是因为jdk1.5后有自动装箱拆箱及机制。在数据被腐乳ArrayList之前自动把他们封装成基本数据类型封装类了。


1.1.2 删——删除

boolean remove(Object obj);删除一个指定对象。如果没有此对象就返回false

boolean removeAll(Collection coll);删除参数容器和本容器中相同的元素。

void clear();直接将容器中的元素清空。


1.1.3 判断

boolean contains(Object obj);是否包含指定元素。

boolean containsAll(Collection coll);是否包含指定容器中的元素。容器中元素发生变化为true

boolean isEmpty();判断集合中是否有元素

public class Day16 {public static void main(String[] args){Collection c = new ArrayList();c.add(2313);c.add(2313);c.add(null);c.add("abcd");c.add("efgh"+'a'+true);int i = 5;c.add(i);c.remove("haha");System.out.println(c);System.out.println(c.contains("haha"));System.out.println(c.containsAll(c));System.out.println(c.isEmpty());System.out.println(c.size());}}

[2313, 2313, null, abcd, efghatrue, 5]
false
true
false
6


1.1.4 查——获取

int size();获取该集合的长度。

Interator iterator();取出元素的手段:迭代器。

boolean retainAll(Collection coll);保留两集合的交集元素并输出判断(有或没有交集)

Object toArray();将集合转成数组。

1.2 迭代器

Iterator iterator();Iterator跟Collection一样,是一个接口。

因为每一个容器的数据结构都不同,所以该迭代器对象是在容器中进行内部实现的,也就是iterator方法在每个容器中的实现方式是不同的。java为了方便我们使用,统一封装成iterator给用户调用。

Iterator接口就是对所有的Collection容器进行元素取出的公共接口。

使用方法:作为集合对象的方法调用。Collection xxx = new ArrayList(); Iterator i = xxx.iterator();得到的不是Iterator实例,而是Iterator的运用于ArrayList的子类,这里运用了多态。

public class Day16{public static void main(String[] args){Collection coll = new ArrayList();coll.add("abc1");coll.add("abc2");coll.add("abc3");coll.add("abc4");//System.out.println(coll.next);System.out.println(coll);//使用iterator调用迭代器,
<span style="white-space:pre"></span>//用while循环Iterator i =  coll.iterator();while(i.hasNext()){System.out.println(i.next());//next是迭代器的方法}//用for循环for(Iterator i1 = coll.iterator();i1.hasNext();){System.out.println(i1.next());}}

PS: 注意用while方法的话在循环完毕后迭代器iterator仍会存在。如果用for循环则可以在循环完毕后释放iterator,更干净。

注意使用迭代器iterator过程中,最好不要对集合进行操作,因为迭代器是事先读取集合长度后操作的,是属于迭代器的动作,如果同时进行了增删这个集合操作,则迭代器不知道读不读,应该读到哪里,即引发了并发操作异常。

所以在迭代器里,只能用迭代器的方法操作数据。原本的iterator迭代器只提供了move操作,即从集合中去除该元素。

如果我们需要对迭代中做更多的增删改查操作,就可以运用List类特有的迭代器ListIterator。

它具有add() set() 等方法。同时还有向前迭代的功能hasPrevious,previous

注意迭代器在循环中迭代完一次之后,不会回复首位的,它的状态已经被记录,如果再用它去迭代一次,只能一致输出null。

public class Day16{public static void main(String[] args){List l = new ArrayList();l.add("abc1");l.add("abc2");l.add("abc3");System.out.println("list="+l);Iterator i  = l.iterator();while(i.hasNext()){//i.next() = "abc";Object o = i.next();System.out.println(o);//System.out.println(i.next());}}}


2 List、set

Collection的两个重要接口(仍然是一个接口)

——List:有序(存入和取出的顺序一致),元素都有索引(或角标),允许重复元素

——Set:元素不能重复,无序。(注意这里的无序不是说它的数据随机存放,而是不按照添加顺序存放——因为他们有自己的排序方式。HashSet是按HashCode和内容,TreeSet是按比较器comparator或让类本身具备可比性comparable)

2.1 List

除了Collection的方法,其特有的常见方法,基本是操作角标的方法(因为List有角标):

2.1.1 添加

void add(int index,E element):将元素插入指定角标位置。

boolean addAll(int index,collection c):将参数容器中的元素插入指定位置角标。

2.1.2 删除

Object remove(index);删除指定角标的元素

2.1.3 修改(因为有List有角标,所以允许修改操作)

Object set(index,element);指定角标修改元素

2.1.4 获取

Object get(index);获取特定角标的元素;

int indexOf(object);根据元素获取元素第一次的角标。如果没有元素,返回-1.

int lastIndexOf(object);根据元素获取元素最后出现的角标。

List subList(int from, int to);获取列表中的一部分,包含fromIndex,不包含toIndex。

PS:正因为List接口有角标,它可以按照角标来操作,比如按角标获取元素。所以List接口的子类对象除了按照Collection的方法使用迭代器iterator之外,还可以像传统的数组一样获用角标获取。

public class Day16{public static void main(String[] args){List l = new ArrayList();for (int x=0;x<10;x++){l.add("haha_"+(x+10));}System.out.println(l);Iterator i = l.iterator();while(i.hasNext()){System.out.print(i.next());}System.out.println();System.out.println("\r\n"+"-------------");for(Iterator i1=l.iterator();i1.hasNext();){System.out.print(i1.next());}System.out.println();System.out.println("\r\n"+"-------------");for(int x=0;x<l.size();x++){//角标取值,List接口特有的方法,因为List有角标System.out.print(l.get(x));}}}


3 List下面的主要类

List:

——Vector:内部是数组结构,是同步的。增删,查询都很慢

——ArrayList:内部是数组结构,是不同步的,替代了Vector。查询速度快,增删速度慢。

——LinkedList:内部是链表结构,是不同步的,增删的速度很快,查询速度慢。


3.1 LinkedList特有的主要方法

因为LinkedList是链表结构,只有索引,没有角标,所以它没有按照角标操作的方法。

增加

addFirst();将指定元素放入LinkList开头,

addLast();将指定元素放入LInkList结尾。

在jdk1.6后,他们分别被offerFirst(); offerLast();代替,没有区别。


获取

getFirst();按索引顺序获取,但不移除,如果链表为空,抛出NoSuchElementException

getLast();按倒叙的索引顺序获取,但不移除

jdk1.6后更新方法peekFirst();替代getFirst(),peekLast();替代getLast();获取但不移除,如果链表为空,返回null

removeFirst();获取并移除,如果链表为空,抛出NoSuchElementException

removeLast();

jdk1.6后更新方法为pollFirst();替代removeFirst();获取并移除,如果链表为空,返回null。pollLast();同理。

package demo;import java.util.*;public class Day17 {public static void main(String[] args){LinkedList lk = new LinkedList();lk.add("haha1");lk.addFirst("haha2");lk.addLast("haha3");System.out.println(lk);Iterator i = lk.iterator();while(i.hasNext()){System.out.println(i.next());}System.out.println("-----------");for(Iterator i1 =lk.iterator();i1.hasNext();)System.out.println(i1.next());System.out.println("-----------");Iterator i2 = lk.iterator();String[] s=new String[lk.size()];int x = 0;while(i2.hasNext()){s[x]=(String)i2.next();x++;}for(String str:s){System.out.println(str);}System.out.println("-----------");while(lk.peek()!=null){//while(true){System.out.println(lk.poll());}//System.out.println(lk);//while(true){//System.out.println();//}}}

注意第二次用lk的迭代器必须要再创建一个Iterator i2,否则会全部输出null


4 Set

4.1 Set是跟List区分开的一个接口,其元素不可以重复,而且无序。

——HashSet:内部哈希表结构,是不同步的。

——TreeSet:可以对Set集合中的元素进行排序,是不同步的。

public class Day17{public static void main(String[] args){Set s = new HashSet();s.add("haha1");s.add("haha2");s.add("haha3");s.add("haha4");Iterator i = s.iterator();while (i.hasNext())System.out.println(i.next());}}
haha4
haha3
haha2
haha1

并非按照输入顺序输出,而是按照Hash地址输出。


4.2 HashSet用哈希表确定元素是否相同。

①先判断两个元素的哈希值是否相同。用HashCode()方法得到元素的哈希值。

②如果相同,再判断两个对象的内容是否相同(因为有可能两个元素被人为设定为同一个哈希值)。用的是equals方法。

如果HashCode不同,就不再判断内容equals

/*在HashSet集合中存储Person对象,如果姓名和年龄相同,视为同一人,是为相同元素 *  */class Person{private String name;private int age;Person(String name,int age){this.name=name;this.age=age;}public String getName(){return name;}public int getAge(){return age;}public int hashCode(){//System.out.println(name.hashCode());return name.hashCode()+age*11;}public boolean equals(Object obj){if(!(obj instanceof Person))throw new ClassCastException("类型错误");Person p = (Person)obj;return this.name.equals(p.name)&&this.age==p.age;}}class Day17{public static void main(String[] args){HashSet hs = new HashSet();hs.add(new Person("zhangsan",10));hs.add(new Person("lisi",14));hs.add(new Person("wangwu",12));hs.add(new Person("zhangsan",10));System.out.println(hs);Iterator i = hs.iterator();while(i.hasNext()){Person obj = (Person)i.next();System.out.println(obj.getName()+"..."+obj.getAge());}}}
[demo.Person@aa9c30e2, demo.Person@d09b2ca5, demo.Person@32b12d]
zhangsan...10
wangwu...12
lisi...14


PS:HashSet判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals。


4.3 LinkedHashSet

LinkedHashSet可以使其无序变有序,但仍然不可重复。

public class Day17{public static void main(String[] args){LinkedHashSet lh = new LinkedHashSet();lh.add("zhangsan"); lh.add("lisi");     lh.add("wangwu");   lh.add(10); lh.add("wangwu");System.out.println(lh);}}
[zhangsan, lisi, wangwu, 10]


4.4 TreeSet

TreeSet底层是二叉树结构。可以给set集合中的元素进行指定顺序排序,默认情况下是通过元素自然顺序排序的。

保证元素元素唯一性的依据是看compareTo方法返回结果是否为0,是0就视为相同,不存。(而HashSet是根据hashCode和equals的判断来保证为一)



如果不要按照对象中具备的自然顺序进行排序。或者对象不具备自然排序,就让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法,

然后把其对象传入集合作为集合使用的比较器。

blic class Day17{public static void main(String[] args){TreeSet<String> ts = new TreeSet(new LengthCom());ts.add("hahaaaa");ts.add("heheaa");ts.add("xixia");ts.add("wuwuaaaa");System.out.println(ts);}}class LengthCom implements Comparator{public int compare(Object o1,Object o2){String s1 = (String)o1;String s2 = (String)o2;return(s1.length()-s2.length());}}
这是按照字符串长度来让TreeSet排序

PS:如果类本身实现了Comparable接口,覆盖了comparaTo(Object o)方法,即自身具备了比较性,而同时TreeSet的构造函数中也传入了比较器Comparator(覆盖了compare(Object o1,Object o2)方法),那么将以比较器的比较规则为准。


4.5 Vector

Vertor的一个特殊方法:

Enumeration elements();Enumeration是一个接口,它生产一系列元素,一次生成一个。该方法类似调用迭代器,为早期使用的方法。

Boolean hasMoreElements();判断是否有下一个元素。

nextElements();获取下一个元素。

0 0
原创粉丝点击