黑马程序员——集合Collection:体系详述

来源:互联网 发布:java统计在线人数 编辑:程序博客网 时间:2024/06/05 18:53

------<ahref="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

集合框架概述

集合体系结构图

集合框架内错综复杂的继承关系、以及各种不同的接口和类与其通过语言来描述,不如用图片来进行最为直观的展示。以下所展示的图片是集合框架的最新版本的体现。

接口和类的区分图


继承关系简图


继承关系详图


集合的基本特点

1,集合是存储对象最常用的一种方式
2,集合是一种容器,有了集合便可以十分方便地对多个对象进行操作
3,集合的长度是可变的,而数组的长度却是固定的
4,集合只能存对象,数组可以存基本数据类型
5,集合可以存不同类型的对象
6,集合中存储的都是对象的引用(地址)

Collection

Collection接口的通用方法

Collection定义了集合框架的共性功能。其下两个主要的子接口有:List(列表),Set(集)。

增加:

add方法的参数类型是Object。以便于接收任意类型对象。
add(e);
addAll(collection);
import java.util.ArrayList;class  CollectionDemo{public static void main(String[] args) {//创建一个集合容器。使用Collection接口的子类。ArrayListArrayList al = new ArrayList();//1,添加元素。al.add("java01");//add(Object obj);容器内添加的对象是任意类型的,类型不确定,需要用父类,此处是多态al.add("java02");al.add("java03");al.add("java04");//打印原集合。sop("原集合:"+al);//输出:原集合:[java01, java02, java03, java04]}public static void sop(Object obj){System.out.println(obj);}}

删除:

remove(e);
removeAll(collection);
clear();
import java.util.ArrayList;class  CollectionDemo{public static void main(String[] args) {//创建一个集合容器。使用Collection接口的子类。ArrayListArrayList al = new ArrayList();//1,添加元素。al.add("java01");//add(Object obj);容器内添加的对象是任意类型的,类型不确定,需要用父类,此处是多态al.add("java02");al.add("java03");al.add("java04");//打印原集合。sop("原集合:"+al);//输出:原集合:[java01, java02, java03, java04]//2,删除元素。al.remove("java02");//输出:remove后集合:[java01, java03, java04]sop("remove后集合:"+al);al.clear();//清空集合。sop("clear后集合:"+al);//输出:clear后集合:[]}public static void sop(Object obj){System.out.println(obj);}}

判断:

contains(e);
isEmpty();
</pre><pre name="code" class="java">import java.util.ArrayList;class  CollectionDemo{public static void main(String[] args) {//创建一个集合容器。使用Collection接口的子类。ArrayListArrayList al = new ArrayList();//1,添加元素。al.add("java01");//add(Object obj);容器内添加的对象是任意类型的,类型不确定,需要用父类,此处是多态al.add("java02");al.add("java03");al.add("java04");sop("原集合:"+al);//输出:原集合:[java01, java02, java03, java04]//2,删除元素。al.remove("java02");//输出:remove后集合:[java01, java03, java04]sop("remove后集合:"+al);al.clear();//清空集合。sop("clear后集合:"+al);//输出:clear后集合:[]//3,判断元素。sop("java03是否存在:"+al.contains("java03"));//输出:java03是否存在:falsesop("集合是否为空?"+al.isEmpty());//输出:集合是否为空?true(此时集合长度为零)}public static void sop(Object obj){System.out.println(obj);}}

获取交集:

retainAll();
import java.util.ArrayList;class  CollectionDemo{public static void main(String[] args) {//创建一个集合容器。使用Collection接口的子类。ArrayListArrayList al1 = new ArrayList();//al1添加元素al1.add("java01");al1.add("java02");al1.add("java03");al1.add("java04");ArrayList al2 = new ArrayList();//al2添加元素al2.add("java01");al2.add("java02");al2.add("java08");al2.add("java09");al2.add("java10");//al1.retainAll(al2)al1.retainAll(al2);sop("al1:" + al1);//输出:al1:[java01, java02]sop("al2:" + al2);//输出:al2:[java01, java02, java08, java09, java10]//al2.retainAll(al1)al2.retainAll(al1);sop("al2:" + al2);//输出:al2:[java01, java02]}

取出元素:

目的是要取出元素并操作元素,所以光靠打印出集合是远远不够的。
iterator();
size();

迭代器接口Iterator

对于集合的元素取出这个动作:用一个函数来描述不够,需要用多个功能来体现,所以就将取出这个动作封装成一个对象来描述。把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,那么取出方式就被定义成了内部类。
而每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都具有共性内容: 判断和取出。那么就可以将这些共性抽取,这些内部类都符合一个规则(或者说都抽取出来一个规则),该规则就是Iterator。
通过一个对外提供的方法:iterator();,来获取集合的取出对象。

迭代的常见操作

boolean hasNext();//有下一个元素,返回真
E next();//取出下一个元素
void remove();//移除
注:在迭代时循环中next调用一次,就要hasNext判断一次。

import java.util.ArrayList;import java.util.Iterator;class  CollectionDemo{public static void main(String[] args) {//创建一个集合容器。使用Collection接口的子类。ArrayListArrayList al = new ArrayList();//al添加元素al.add("java01");al.add("java02");al.add("java03");al.add("java04");//利用迭代器获取元素的基本方法Iterator it = al.iterator();//获取迭代器,取出集合中的元素//接口型引用只能指向自己的子类对象,而且该对象并不是被new()出来的,是通过al这个ArrayList调用了iterator()方法获取出来的//sop(it.next());//java01//sop(it.next());//java02//sop(it.hasNext());//truewhile(it.hasNext()){//iterator中的hasNext方法,只要集合中还有下一个元素,就返回真sop(it.next());//iterator中的next方法,取出下一个元素,并通过sop打印}/*  输出:  java01java02java03java04 */}public static void sop(Object obj){System.out.println(obj);}}/*while代码块如果用for来写,格式如下:for(Iterator it = al.iterator(); it.hasNext() ; ){System.out.println(it.next());}使用for来写,避免了循环结束后it还在内存中  */

迭代器使用注意事项

1,迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
2,迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
3,迭代器的next方法返回值类型是Object,所以要记得类型转换。

import java.util.ArrayList;import java.util.Iterator;class  CollectionDemo{public static void main(String[] args) {//创建一个集合容器。使用Collection接口的子类。ArrayListArrayList al = new ArrayList();//al添加元素al.add("java01");al.add("java02");al.add("java03");al.add("java04");//利用迭代器获取元素的基本方法Iterator it = al.iterator();//获取迭代器,取出集合中的元素//接口型引用只能指向自己的子类对象,而且该对象并不是被new()出来的,是通过al这个ArrayList调用了iterator()方法获取出来的//sop(it.next());//java01//sop(it.next());//java02//sop(it.hasNext());//truewhile(it.hasNext()){//iterator中的hasNext方法,只要集合中还有下一个元素,就返回真sop(it.next());//iterator中的next方法,取出下一个元素,并通过sop打印}/*  输出:  java01java02java03java04 */}public static void sop(Object obj){System.out.println(obj);}}/*while代码块如果用for来写,格式如下:for(Iterator it = al.iterator(); it.hasNext() ; ){System.out.println(it.next());}使用for来写,避免了循环结束后it还在内存中  */

List

体系概述

Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
|--Set:元素是无序,元素不可以重复。

List特有方法

增加:

add(index,element);
addAll(index,Collection);
import java.util.*;class ListDemo {public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//输出:原集合是:[java01, java02, java03]//在指定位置添加元素。al.add(1,"java09");//在脚标为1的位置插入java09这个元素sop("改变后的集合是:"+al);//输出:改变后的集合是:[java01, java09, java02, java03]}}

删除:

remove(index);
import java.util.*;class ListDemo {public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//输出:原集合是:[java01, java02, java03]//在指定位置添加元素。al.add(1,"java09");sop("改变后的集合是:"+al);//输出:改变后的集合是:[java01, java09, java02, java03]//删除指定位置的元素。al.remove(2);//移除脚标为2的位置的元素sop("remove后的集合是:"+al);//remove后的集合是:[java01, java09, java03]}}

修改:

set(index,element);
import java.util.*;class ListDemo {public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//输出:原集合是:[java01, java02, java03]//在指定位置添加元素。al.add(1,"java09");sop("改变后的集合是:"+al);//输出:改变后的集合是:[java01, java09, java02, java03]//删除指定位置的元素。al.remove(2);//移除脚标为2的位置的元素sop("remove后的集合是:"+al);//remove后的集合是:[java01, java09, java03]//修改元素。al.set(2,"java007");//在脚标为2的位置,修改原来的元素的值sop("set后的集合是:"+al);//输出:set后的集合是:[java01, java09, java007]}}

获取:

get(index):
subList(from,to);
listIterator();
int indexOf(obj):获取指定元素的位置。
ListIterator listIterator();
import java.util.*;class ListDemo {public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//输出:原集合是:[java01, java02, java03]//添加al.add(1,"java09");sop("改变后的集合是:"+al);//输出:改变后的集合是:[java01, java09, java02, java03]//删除al.remove(2);//移除脚标为2的位置的元素sop("remove后的集合是:"+al);//remove后的集合是:[java01, java09, java03]//修改al.set(2,"java007");//在脚标为2的位置,修改原来的元素的值sop("set后的集合是:"+al);//输出:set后的集合是:[java01, java09, java007]//获取//get(index):位置->元素//如果al.get(1)写在此处,然后再直接打印al,输出的还是[java01, java09, java007],因为仅仅是在查看sop("get(1)获得的元素是:" + al.get(1));//输出:get(1)获得的元素是:java09//获取所有元素。for(int x=0; x<al.size(); x++)//和数组不同,集合所使用的是size{System.out.println("al("+x+")="+al.get(x));}/*al(0)=java01al(1)=java09al(2)=java007 *///int indexOf(obj)元素->位置sop("index="+al.indexOf("java09"));//输出:index=1//subList(from,to);List sub = al.subList(1,3);//取脚标为1,2的两个元素,包含头,不包含尾sop("sub="+sub);//输出:sub=[java09, java007]}}

ListIterator

ListIterator的特点:
ListIterator是List集合特有的迭代器,是Iterator的子接口。
使用迭代器时的注意事项:
在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常。所以在迭代器时,只能用迭代器的方法操作元素。
需要ListIterator的原因:
Iterator方法是有限的,只能对元素进行判断,取出,删除的操作。如果想要其他的操作,如添加、修改等,就需要使用其子接口:ListIterrator。该接口只能通过List集合的ListIterator方法获取。

ListIterator的特有方法

add(obj);//增加
set(obj);//修改为obj
hasPrevious();//判断前面有没有元素
previous();//取前一个元素
import java.util.*;class ListIteratorDemo{public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {//新建一个ArrayList,并添加3个元素ArrayList aL = new ArrayList();aL.add("java01");aL.add("java02");aL.add("java03");sop(aL);/* //在迭代过程中,准备添加或者删除元素。Iterator it = al.iterator();//此时把元素的引用又取到迭代器中去了//操作元素既可以用add,也可以用迭代器,但是不能同时使用,会发生ConcurrentModificationException异常while(it.hasNext()){Object obj = it.next();if(obj.equals("java02"))//调用Object类的equals方法//al.add("java008");it.remove();//将java02的引用从集合中删除了。使用了Iterator的remove功能,不过移除的仅仅是集合中元素的引用//但是Iterator中没有add功能,要用迭代器来添加元素,考虑用ListIteratorsop("obj="+obj);//输出:obj1=java01 \n obj2=java02 \n obj3=java03,元素的引用移除了,元素还在内存中,并还在被obj使用,java02还能打出 }sop(al);//输出:[java01,java03],移除后al的结果*///新建一个ListIterator对象//使用ListIterator的add方法 for(ListIterator li = aL.listIterator(); li.hasNext() ; ) {Object obj = li.next();if(obj.equals("java02"))li.add("java009"); } sop(aL);//输出:[java01, java02, java009, java03],在java02这个元素后面插入一个java009的新元素//使用ListIterator的set方法for(ListIterator li = aL.listIterator(); li.hasNext() ;)//如果使用while的方式,则hasnext()直接为flase,因为li还在内存中{Object obj = li.next();if(obj.equals("java02"))li.set("java006");//把java02的位置替换为Java006}sop(aL);//输出:[java01, java006, java009, java03]//使用ListIterator的hasPrevious、previous方法ListIterator li = aL.listIterator();while(li.hasNext()){sop("next::"+li.next());}while(li.hasPrevious()){sop("pres::" + li.previous());/* pres::java03pres::java009pres::java006pres::java01 */}}}

Enumeration:Vector

枚举就是Vector特有的取出方式。发现枚举和迭代器很像,其实枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
特有方法:
addElement(obj);//添加元素,相当于add(obj);
Enumerationelements();//Vector特有取出方式(枚举)
hasMoreElements();//相当于Iterator的hasNext()方法
nextElements();//相当于Iterator的next()方法

LinkedList特有方法

增加:

addFirst();
addLast();
import java.util.*;class LinkedListDemo {public static void main(String[] args) {LinkedList link = new LinkedList();//addLast方法:尾端插入link.addLast("java01");link.addLast("java02");link.addLast("java03");link.addLast("java04");sop(link);//输出:[java01, java02, java03, java04]//addFirst方法:首端插入link.addFirst("java11");link.addFirst("java22");link.addFirst("java33");link.addFirst("java44");sop(link);//输出:[java44, java33, java22, java11, java01, java02, java03, java04]}public static void sop(Object obj){System.out.println(obj);}}

获取:

1,获取但不删除
getFirst();
getLast();
2,获取但删除
removeFirst();
removeLast();
package collection;import java.util.*;class LinkedListDemo {public static void main(String[] args) {LinkedList link = new LinkedList();link.add("java01");link.add("java02");link.add("java03");link.add("java04");sop(link);//输出:[java01, java02, java03, java04]//getFisrtsop(link.getFirst());//输出:java01//getLastsop(link.getLast());//输出:java04//removeFirstwhile(!link.isEmpty()){sop(link.removeFirst());/* java01java02java03java04 */}//removeLastwhile(!link.isEmpty()){//仅为演示用,实际过程中,此处link已经是空的,不会输出sop(link.removeLast());}/* java04java03java02java01 */}public static void sop(Object obj){System.out.println(obj);}}

JDK6更新方法:
1、增
offFirst();
offLast();
2、获取:获取元素,但是不删除。如果集合中没有元素,会返回null。
peekFirst();
peekLast();
3、删:获取元素,并删除元素。如果集合中没有元素,会返回null。
pollFirst();
pollLast();
与老方法的区别:
老方法:如果集合中没有元素,会出现NoSuchElementException
新方法:如果集合中没有元素,会返回null。

ArrayList应用实例

关键点:
contains方法在判断是否存在该元素的时候,其实是在用对象的equals方法在和对象进行比较,看对象与对象是否相同
如果要自定义新的equals规则,需要复写对(shang)象(di)的equals方法。
package collection;import java.util.*;/*将自定义对象作为元素存到ArrayList集合中,并去除重复元素。比如:存人对象。同姓名同年龄,视为同一个人。为重复元素。思路:1,对人描述,将数据封装进人对象。2,定义容器,将人存入。3,取出。List集合判断元素是否相同,依据是元素的equals方法。*/class Person{private String name;private int age;Person(String name,int age)//构造器{this.name = name;this.age = age;}//开发时使用setter和getterpublic String getName(){return name;}public int getAge(){return age;}//equals方法:判断对象是否相同public boolean equals(Object obj)//此处的equals对象的equals方法(上帝的方法),根据自定义的要求,复写该equals方法//在容器比较元素是否相同,使用的是equals方法,用对象的equals和另一个对象在比较{if(!(obj instanceof Person))return false;Person p = (Person)obj;//向下转型System.out.println(this.name+"....."+p.name);/* 程序输出:主动比较者(this)...被比较者(obj) lisi02.....lisi01lisi04.....lisi01lisi04.....lisi02lisi03.....lisi01lisi03.....lisi02lisi03.....lisi04lisi04.....lisi01lisi04.....lisi02lisi04.....lisi04lisi03.....lisi01lisi03.....lisi02lisi03.....lisi04lisi03.....lisi03 */return this.name.equals(p.name) && this.age == p.age;//返回真就说明相同,返回假就说明不同//此处的equals是调用字符串的equals方法}}class ArrayListTest{public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {ArrayList al = new ArrayList();//ArrayList容器不知道元素相同的条件al.add(new Person("lisi01",30));//其实在存的时候存的是al.add(Object obj);,只有Object才能接收任意对象//把Person往里面传的时候,其实是这样:Object obj = new Person("lisi01",30);类型被提升了//使用next时,返回的是Object,Object中没有Person特有的方法,如果还想要再得到Person类中的方法,需要向下转型al.add(new Person("lisi02",32));al.add(new Person("lisi04",35));al.add(new Person("lisi03",33));al.add(new Person("lisi04",35));//sop(al);//使用singleElement(al)方法后,去掉了重复元素al = singleElement(al);sop("remove 03 :"+al.remove(new Person("lisi03",33)));//remove方法底层也是依赖于元素的equals方法。Iterator it = al.iterator();while(it.hasNext()){Person p = (Person)it.next();//next()返回的是已经被提升的类型,需要子类对象特有的方法(此处如getName)时,需要先向下转型/* 其实是两句话的简化 Object obj = it.next(); Person p =(Person)obj; 意思就是把obj变成Person类型,然后赋给p */sop(p.getName()+"::"+p.getAge());}}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))//contains方法在判断是否存在该元素的时候,其实是在用对象的equals方法在和对象进行比较,看对象与对象是否相同//如果要自定义新的equals规则,需要复写对象的equals方法//1.lisi01先传入到contains的obj中//2.lisi01被添加进newA1这个集合中//3.lisi02被传入到contains的obj中//4.程序跳转到public boolean equals(Object obj),开始进行equals的比较//5.因为第一个对象lisi01并没有其他对象与之比较,所以直接被传入到newAl中,而第二个对象lisi02则需要调用equals方法与第一个传入的对象lisi01进行比较//6.equals在Object类的源码中的语句是:public boolean equals(Object obj) {return (this == obj)},第一次比较时,obj是lisi01,this是lisi02//7.因为newAl.contains(obj)第一次比较时,相当于lisi02.equals(lisi01),因为lisi01是先存在的,用后来的和先来的比较//8.那么lisi01就传入public boolean equals(lisi01)newAl.add(obj);}return newAl;}}

Set

Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。     
|--HashSet:底层数据结构是哈希表。线程不同步。 保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true。
|--TreeSet:可以对Set集合中的元素进行排序。默认按照字母的自然排序。底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0。
Set集合的功能和Collection是一致的。

HashSet

底层实现及概念

HashSet的底层是hashtable

基本功能


碰撞的解决方法之1:Open Addressing

碰撞解决方法之2:Separate Chaining


HashSet中保证元素唯一性的方法:

通过元素的hashcode加equals方法,如果hashcode相同,再用Object的equals方法来判断元素是否相同,要注意先判断的是hashcode

注意:
1,直接打印对象时,调用对象的toString方法,其底层实现是getClass().getName() + '@' + Integer.toHexString(hashCode())
2,我们所看到的@后面的值是对象的hashCode,和真实物理地址并不相同

在HashSet中存入自定义对象

package collection;import java.util.*;/*往hashSet集合中存入自定对象姓名和年龄相同为同一个人,重复元素。*/class HashSetDemo{public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {//创建一个HashSetHashSet hs = new HashSet();//在HashSet中存入元素hs.add(new Person4("a1",11));hs.add(new Person4("a2",12));hs.add(new Person4("a3",13));hs.add(new Person4("a2",12));//重复的元素//sop("a1:"+hs.contains(new Person("a2",12)));//hs.remove(new Person("a4",13));//取出HashSet中的元素Iterator it = hs.iterator();while(it.hasNext()){Person4 p = (Person4)it.next();sop(p.getName()+"::"+p.getAge());}}}class Person4{private String name;private int age;Person4(String name,int age){this.name = name;this.age = age;}//复写Object类的hashCode方法public int hashCode(){System.out.println(this.name+"....?hashCode");return name.hashCode()+age*37;//如果return了固定值,如return 60,那么所有元素hashcode相同,会不断调用equals方法,效率较低//name.hashCode()调用了String复写Object类的hashCode方法//字符串的hashCode的计算公式为:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]//age乘以一个数是为了防止这样的情况发生:Stringobj1.hashCode() + Stringobj2.age = Stringobj2.hashCode() + Stringobj1.age}//建立Person对象自己的hashCodepublic String getName(){return name;}public int getAge(){return age;}//复写Object类的equals方法public boolean equals(Object obj){if(!(obj instanceof Person4))return false;Person4 p = (Person4)obj;System.out.println(this.name+"...equals?.."+p.name);return this.name.equals(p.name) && this.age == p.age;}}/*输出结果://System.out.println(this.name+"....?hashCode");a1....?hashCodea2....?hashCodea3....?hashCodea2....?hashCode//System.out.println(this.name+"...equals?.."+p.name);a2...equals?..a2//sop(p.getName()+"::"+p.getAge());a3::13a1::11a2::12*/

TreeSet

底层实现及概念

与HashSet相比最大的特点:
可以对Set集合中的元素进行排序。

实现TreeSet排序的两种方式

1,让元素自身具备比较性

元素需要实现Comparable接口,覆盖compareTo方法。也种方式也成为元素的自然顺序,或者叫做默认顺序。

2,让集合自身具备比较性

当元素自身不具备比较性时,或、比较性并非所需。这时就要让集合自身具备比较性。在集合初始化时,就有了比较方式。

TreeSet底层数据结构:红黑树



TreeSet排序1:让元素自身具备比较性

package collection;/* 需求:往TreeSet集合中存储自定义对象学生。想按照学生的"年龄"进行排序。 */import java.util.*;class TreeSetDemo {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Student("lisi02",22));ts.add(new Student("lisi007",20));ts.add(new Student("lisi09",19));ts.add(new Student("lisi08",19));//ts.add(new Student("lisi007",20));//如果比完此处的主要条件:年龄之后,不再比较一下次要条件:姓名,那么当年龄相同而姓名不同的人存进来以后,将不会被存入Iterator it = ts.iterator();while(it.hasNext()){Student stu = (Student)it.next();System.out.println(stu.getName()+"..."+stu.getAge());}}}//告诉TreeSet用哪种方式进行排//TreeSet本身需要进行排序,但是它并不知道以怎样的方式排,如果不让存入的对象具备比较性,会产生ClassCastException//让元素自身具备比较性:1.实现Comparable接口class Student implements Comparable//该接口强制让学生具备比较性。{private String name;private int age;Student(String name,int age){this.name = name;this.age = age;}//让元素自身具备比较性:2.复写compareTo方法public int compareTo(Object obj){//return 0;if(!(obj instanceof Student))throw new RuntimeException("不是学生对象");Student s = (Student)obj;//向下转型System.out.println(this.name+"....compareto....."+s.name);if(this.age>s.age)return 1;//返回负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。 if(this.age==s.age){return this.name.compareTo(s.name);//比较完主要条件之后再比较次要条件//用compareTo方法之后,当年龄相同时,还会按照姓名的顺序进行排序输出//String类中本身就包含compareTo方法/* 按字典顺序比较两个字符串。该比较基于字符串中各个字符的 Unicode 值。 按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。 如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。 如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。 如果这两个字符串相等,则结果为 0;compareTo  只在方法 equals(Object) 返回 true 时才返回 0。 */}return -1;}public String getName(){return name;}public int getAge(){return age;}}

正序和逆序输出的方式

class TreeSetOptDemo {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Student2("lisi02",17));ts.add(new Student2("lisi007",20));ts.add(new Student2("lisi09",19));ts.add(new Student2("lisi08",19));ts.add(new Student2("lisi06",19));//如果比完此处的主要条件:年龄之后,不再比较一下次要条件:姓名,那么当年龄相同而姓名不同的人存进来以后,将不会被存入Iterator it = ts.iterator();while(it.hasNext()){Student2 stu = (Student2)it.next();System.out.println(stu.getName()+"..."+stu.getAge());}}}//告诉TreeSet用哪种方式进行排//TreeSet本身需要进行排序,但是它并不知道以怎样的方式排,如果不让存入的对象具备比较性,会产生ClassCastException//让元素自身具备比较性:1.实现Comparable接口class Student2 implements Comparable//该接口强制让学生具备比较性。{private String name;private int age;Student2(String name,int age){this.name = name;this.age = age;}//让元素自身具备比较性:2.复写compareTo方法public int compareTo(Object obj){return 1;//1代表后存入的对象总是比先存入的对象大,取的时候默认方式是从小到大取出//结果是按照存入的顺序输出/* return1输出结果: lisi02...17lisi007...20lisi09...19lisi08...19lisi06...19 return-1输出结果: lisi06...19lisi08...19lisi09...19lisi007...20lisi02...17 */}public String getName(){return name;}public int getAge(){return age;}}

TreeSet排序2:让集合自身具备比较性

TreeSet(Comparator<? super E> comparator) 
 构造一个新的空 TreeSet,它根据指定比较器进行排序。
注意:comparator接口里面需要复写compare方法,comparable接口里面需要复写的是compareTo方法
import java.util.*;//假设原来按照年龄排序的代码已经固定,现在想在不改变原来代码的基础上,重新按照姓名进行排序//原来已经固定的代码部分class Student implements Comparable//该接口强制让学生具备比较性。{private String name;private int age;Student(String name,int age){this.name = name;this.age = age;}public int compareTo(Object obj){if(!(obj instanceof Student))throw new RuntimeException("不是学生对象");Student s = (Student)obj;//System.out.println(this.name+"....compareto....."+s.name);if(this.age>s.age)return 1;if(this.age==s.age){return this.name.compareTo(s.name);}return -1;}public String getName(){return name;}public int getAge(){return age;}}class TreeSetDemo2 {public static void main(String[] args) {/* 使用TreeSet默认构造函数,不传入MyCompare时的结果: TreeSet ts = new TreeSet(); 按照原来年龄的方式排序 lisi06...18lisi09...19lisi007...20lisi02...21lisi02...22lisi007...29使用TreeSet超载构造函数,传入MyCompare类时的结果:TreeSet ts = new TreeSet(new MyCompare());按照新的姓名的方式排序lisi007...20lisi007...29lisi02...21lisi02...22lisi06...18lisi09...19 *///TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。TreeSet ts = new TreeSet(new MyCompare());ts.add(new Student("lisi02",22));ts.add(new Student("lisi02",21));ts.add(new Student("lisi007",20));ts.add(new Student("lisi09",19));ts.add(new Student("lisi06",18));ts.add(new Student("lisi06",18));ts.add(new Student("lisi007",29));//ts.add(new Student("lisi007",20));//ts.add(new Student("lisi01",40));Iterator it = ts.iterator();while(it.hasNext()){Student stu = (Student)it.next();System.out.println(stu.getName()+"..."+stu.getAge());}}}//TreeSet排序方式二:让集合自身具备比较性class MyCompare implements Comparator{public int compare(Object o1,Object o2){Student s1 = (Student)o1;Student s2 = (Student)o2;int num = s1.getName().compareTo(s2.getName());//此处的compareTo是调用String复写Object类的compareTo方法,该方法会根据比较结果返回值//主要条件相同时再比较次要条件if(num==0){return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));//数字也可以排序,此处调用Integer整数类复写的compareTo方法//把年龄先封装成整数对象再调用Integer的compareTo方法//将new Integer(s1.getAge())和new Integer(s2.getAge())进行比较/*if(s1.getAge()>s2.getAge())return 1;if(s1.getAge()==s2.getAge())return 0;return -1;*/}return num;}}

Map

基本概念

Map的分类:
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0,效率低。
|--HashMap:底层是哈希表数据结构。允许使用null键null值,该集合是不同步的。JDK1.2,效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给Map集合中的键进行排序。
Map的特点:
1,该集合存储键值对,一对一对往里存,要保证键的唯一性。
2,Set集合的底层就是Map

常用操作方法

1,添加。
put(K key, V value) 
putAll(Map<? extends K,? extends V> m) 
2,删除。
clear() 
remove(Object key) 
3,判断。
containsValue(Object value) 
containsKey(Object key) 
isEmpty() 
4,获取。
get(Object key) 
size() //获取长度
values() //获取元素的value

entrySet() 
keySet() 

import java.util.*;class  MapDemo{public static void main(String[] args) {Map<String,String> map = new HashMap<String,String>();//添加元素//Collection中的add方法返回的是boolean,而put方法返回的是该键被存入后原来的值//如果出现添加相同的键时,那么后添加的值会覆盖原有键对应值。//并put方法会返回被覆盖的值。System.out.println("put01:"+map.put("01","zhangsan1"));//输出:put01:nullSystem.out.println("put01:"+map.put("01","wangwu"));//输出:put01:zhangsan1map.put("02","zhangsan2");map.put("03","zhangsan3");//判断元素System.out.println("containsKey:"+map.containsKey("022"));//输出:containsKey:false//删除元素//键-删-值System.out.println("remove:"+map.remove("02"));//输出:remove:zhangsan2//获取元素System.out.println("get023:"+map.get("023")); //输出:get023:nullSystem.out.println("get01:"+map.get("01")); //输出:get01:wangwumap.put("04",null);//把key"04"存为nullSystem.out.println("get04:"+map.get("04"));//输出:get04:null//hashMap集合中null是可以作为键存在的,hashTable不可存null//可以通过get方法的返回值来判断一个键对应的值是否存在。通过返回null来判断。//获取map集合中所有的值。Collection<String> coll = map.values();System.out.println(coll);//输出:[wangwu, zhangsan3, null] 返回的是Map中的值所组成的CollectionSystem.out.println(map);//输出:{01=wangwu, 03=zhangsan3, 04=null}}}

Map集合的两种取出方式

Map-keySet方式

基本思想:将map集合转成set集合。再通过迭代器取出。
Set<k> keySet方法具体步骤:
1,将map中所有的键存入到Set集合。因为set具备迭代器,所以可以用迭代方式取出所有的键
2,再根据get方法。获取每一个键对应的值。
import java.util.*;class MapDemo2 {public static void main(String[] args) {Map<String,String> map = new HashMap<String,String>();map.put("02","zhangsan2");map.put("03","zhangsan3");map.put("01","zhangsan1");map.put("04","zhangsan4");//1,先获取map集合的所有键的Set集合,keySet();Set<String> keySet = map.keySet();//此处的String代表Key的类型在这里是字符串类型//2,有了Set集合,就可以获取其迭代器拿到KeyIterator<String> it = keySet.iterator();//Iterator的泛型和Set一致,因为是在操作Set中的元素while(it.hasNext()){String key = it.next();//3,有了Key就可以通过map集合的get方法获取其对应的值。String value  = map.get(key);//把get到的key存在名为value的字符串变量中System.out.println("key:"+key+",value:"+value);}/* 程序输出:key:01,value:zhangsan1key:02,value:zhangsan2key:03,value:zhangsan3key:04,value:zhangsan4 */}}

Map-entrySet方式

Set<Map.Entry<k,v>> entrySet 基本思想:将map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是:Map.Entry
Entry其实就是Map中的一个static内部接口,为什么要定义在内部?
因为只有当有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。
import java.util.*;class MapDemo2 {public static void main(String[] args) {Map<String,String> map = new HashMap<String,String>();map.put("02","zhangsan2");map.put("03","zhangsan3");map.put("01","zhangsan1");map.put("04","zhangsan4");//1,将Map集合中的映射关系取出。存入到Set集合中。Set<Map.Entry<String,String>> entrySet = map.entrySet();//Map.Entry是一个代表集合中的映射关系的数据类型//Set内"泛型"要返回的是Map.Entry类型,Map.Entry本身又泛型了<k,v>的类型,这里是<String,String>//2,有了Set集合,就可以获取其迭代器拿到映射关系Iterator<Map.Entry<String,String>> it = entrySet.iterator();//Iterator的泛型和Set一致,因为是在操作Set中的元素while(it.hasNext()){Map.Entry<String,String> me = it.next();//3,拿到了映射关系,就可以用其特有的getKey和getValue方法得到值String key = me.getKey();String value = me.getValue();System.out.println("key:"+key+",value:"+value);}/* 程序输出:key:01,value:zhangsan1key:02,value:zhangsan2key:03,value:zhangsan3key:04,value:zhangsan4 */}}/*Map.Entry 其实Entry也是一个接口,它是Map接口中的一个内部接口。interface Map{public static interface Entry{public abstract Object getKey();public abstract Object getValue();}}class HashMap implements Map{class Haha implements Map.Entry{public  Object getKey(){}//把抽象方法实现public  Object getValue(){}}}*/

Map一对多映射关系实例

/*  "yureban"Student("01" "zhangsan"); Student("02" "lisi");  "jiuyeban"  Student("01" "wangwu"); Student("02" "zhaoliu"); 就如同一个学校有多个教室。每一个教室都有名称。 */  import java.util.*;    class  MapDemo3 {      public static void main(String[] args)       {      //学校集合      HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>();      //预热班集合          HashMap<String,String> yureban=new HashMap<String,String>();          //就业班集合          HashMap<String,String> jiuyeban=new HashMap<String,String>();                  //学校中班级集合和名称的映射          czbk.put("yureban",yureban);          czbk.put("jiuyueban",jiuyeban);               //预热班级中学号与姓名的映射          yureban.put("01","zhangsan");          yureban.put("02","lisi");                 //就业班级中学号与姓名的映射          jiuyeban.put("01","wangwu");          jiuyeban.put("02","zhouqi");                        //直接显示全部学生信息          getAllStudentInfo(czbk);        }          //定义一个方法获取全部学生信息,包括在哪个班级,叫什么名字,学号多少      public static void getAllStudentInfo(HashMap<String ,HashMap<String,String>> hm)      {          for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; )//用keySet取出方式          {              String s= it.next();//班级名称              System.out.println(s+":");              HashMap<String,String> stu=hm.get(s);//班级集合                getStudentInfo(stu);          }      }            //获取班级中学生的信息,包括姓名和学号      public static void getStudentInfo(HashMap<String,String> hm)      {          for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; )          {              String key=it.next();//学号              String value=hm.get(key);//姓名              System.out.println(key+"..."+value);          }      }  }  /* 程序输出结果:jiuyueban:01...wangwu02...zhouqiyureban:01...zhangsan02...lisi */





0 0
原创粉丝点击