标签:
本人正在学习java基础知识,非常感恩能够看到毕向东老师的java视频,他引领了我去思考问题,而不是生硬的去记一些知识点,下面是我对集合学习的总结和思考。
问题1:什么是集合框架?
首先要理解集合这个词,它有另一个更加形象的名词:容器,所谓容器就是装载事物的器皿,而在java中最大的特征就是面向对象,所以可以推断出其实它就是用来装载对象的,便于我们去遍历和处理这些对象,关于框架的含义,其实就是它不是一个单独对象,而是有很多对象,并且相互存在区别和关系。
下图是目前集合的框架图,其中实线是具体的实现类,而虚线是接口或者工具类。
集合框架图
这里要说明的是,原来集合并没有怎么庞大的“家族”,在jdk的api中查看,jdk1.0的时候只有两个类即:Vector和Hashtable,因为后期发展,他们已经不能满足需要,所以2.0以后出现以上的框架图,而主要的优化就是容器丰富了和更加高效。就好比我们以前煮东西只需要一个大铁锅,但是因为后面物质和需求的发展,必须进行精细化,出现更加针对性的炊具。至于它们的优点和区别后面总结。
问题2:java有许多可以装载其它数据的“容器”,比如类、字符串缓冲池等,尤其是数组,不仅可以装载基本数据类型,也可以装载对象,跟我们要学习的集合存在某种程度的冲突,那么他们的区别在哪里?
数组的长度是固定,而集合的长度是可变的,数组一旦初始化以后,它所能装载的对象个数是不能超出它的长度的,而集合创建以后,可以任意的装载对象;具备的现实意义就是,大多数我们的数据是动态的,比如论坛网站的会员信息,门户网站的新闻,社交网站的状态,所以无法在程序中指定一个固定长度数值去装载它,只能要这里的集合去装载。
整个集合框架的学习必须参考上面的集合框架图,首先需要的介绍是Collection,为什么呢?如果你仔细查看上图会发现,它下面有很多分支(向上的尖头指向它),而这正是java继承的特点,就是事物不断向上抽取共性(实际就是指方法),一般顶层都是接口,它包含了子类的共性方法。而我们发现其实集合框架顶层其实只有Collection、Map和Iterator,而Iterator其实不是容器,这一块后面具体介绍,所以首先我们要了解顶层接口有那些共性的方法,然后在去看看不同子类有那些特殊的方法。
而容器从字面来说,它会具备的方法,无非添加、修改、删除、取出等主要功能,翻看API中java.util.Collection的方法:
1、 添加
boolean add(E e);
E可以理解为Object,其它是element(元素)的缩写。
boolean addAll(Colllection<? extends E> c);
<? extends E>是泛型,后面介绍。
2、 删除
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();
移除collection中所有元素。
3、 取出
int size();
Iterator iterator();
迭代器。
4、 判断
boolean isEmpty();
容器中不包含元素,返回true。
boolean contains(object o);
boolean containsAll(Collection<?> c);
如果此collection 包含指定 collection 中的所有元素,则返回true。
retainAll(Collection<?> c);
仅保留此 collection 中那些也包含在指定collection 的元素(可选操作),其实就是数学中的取交集。
对上面介绍的collection方法的进行演示,我们需要寻找它的一个子类,这里就用ArrayList来演示。
import java.util.*; class CollectionDemo { publicstatic void main(String[] args){ //创建容器1 ArrayList<String>coll = new ArrayList<String>(); method1(coll); //创建容器2 ArrayList<Person>coll2 = new ArrayList<Person>(); method2(coll2); //创建容器2 ArrayList<Person>coll3 = new ArrayList<Person>(); method3(coll2,coll3); } publicstatic void method1(Collection<String> coll){ //添加 字符串 coll.add("abc"); coll.add("123"); coll.add("efg"); //打印容器 System.out.println("size:"+coll.size()+","+coll); //包含 System.out.println(coll.contains("123")); //删除 coll.remove("123"); System.out.println("size:"+coll.size()+","+coll); //清除 coll.clear(); System.out.println("isEmpty:"+coll.isEmpty()+","+coll); System.out.println("============method1================="); } publicstatic void method2(Collection<Person> coll){ coll.add(newPerson("zhangsan",23)); coll.add(newPerson("xiaoming",24)); coll.add(newPerson("lisi",25)); coll.add(newPerson("wangwu",26)); System.out.println(coll); //输出集合中每一个元素的字符串表现形式,即调用toString(); //包含 System.out.println(coll.contains(newPerson("lisi",25))); System.out.println(coll.contains("123")); //删除 coll.remove(newPerson("lisi",25)); //打印 System.out.println(coll); System.out.println("============method2================="); } publicstatic void method3(Collection<Person> coll,Collection<Person>coll2){ coll2.add(newPerson("zhangsan",23)); coll2.add(newPerson("xiaoming",24)); //包含-容器 System.out.println(coll.containsAll(coll2)); //删除 //coll.removeAll(coll2); //System.out.println(coll); //合集 coll.retainAll(coll2); System.out.println(coll); System.out.println("============method3================="); } } class Person { privateString name; privateint age; Person(Stringname,int age){ this.name= name; this.age= age; } publicString toString(){ returnname +":"+ age; } publicboolean equals(Object obj) throws ClassCastException{ if(!(obj instanceof Person)) thrownew ClassCastException("不是Person类"); Personp = (Person)obj; returnname.equals(p.name) && age == p.age; } }
注意:在contains和remove方法使用的时候,这里面包含了判断元素是否相等的前提,其实它是调用元素的equals方法,而我们自定义的类是从Object类中继承过来,它比较对象的地址,一般需要根据我们实际情况进行复写。
1、 什么是迭代器?
可以看着获取容器中元素的方法。
2、 迭代器的获取?
Collection中调用iterator()方法。
import java.util.*; class IteratorDemo { publicstatic void main(String[] args){ ArrayList<Person>coll = new ArrayList<Person>(); coll.add(newPerson("李四",23)); coll.add(newPerson("王五",24)); coll.add(newPerson("张三",22)); Iterator<Person>it = coll.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("==================================="); for(Iterator<Person>it2 = coll.iterator();it2.hasNext();){ System.out.println(it2.next()); } } }
1、 为什么要使用迭代器?
集合框架中包含List、Set分支,List下面有(ArrayList、LinkedList),Set下面有(HashSet、TreeSet、LinkedHashSet),它们是不同的容器,最本质的区别就是数据结构不同,即在内存中存放数据的规则不一样。这导致的一个问题,不同容器获取数据的方法是不一样的,比如AarryList是顺序的,可以按角标获取元素get(int index),而set是无序的,不能根据角标去获取元素;在容器使用上是非常不方便的,这时候就需要考虑建立一个统一方法解决这个问题,这就是迭代器的由来。
2、 迭代器的原理?
首先建立统一的方法供调用,实现方式就是让Collection继承了一个Iterable<E>接口,该接口包含iterator()方法,返回一个Iterator<T>接口,这样需要在Collection子类中实现iterator()方法,而实现这个方法最关键的是返回一个Iterator对象,应该怎么做:通过内部类继承Iterator接口,复写它的hasNext()和next()方法,分别表示“如果仍有元素可以迭代,则返回 true”、“返回迭代的下一个元素。”而怎么实现这两个方法,需要根据自身的数据结构。
List:有序,元素可以重复的,元素都有角标。
Set: 无序,元素不可以重复。
最重要的就是元素含有角标,所以可以按角标进行添加、删除、修改和获取。
1、 添加
void add(intindex, E element);
在列表的指定位置插入指定元素
voidadd(int index,Collection<? Extends E> c);
将指定 collection 中的所有元素都插入到列表中的指定位置
2、 删除
E remove(intindex);
移除列表中指定位置的元素。注意:方法返回被移除的元素。
3、 修改
E set(intindex,E element);
用指定元素替换列表中指定位置的元素;注意:返回替换前的元素。
4、 获取
E get(intindex);
返回列表中指定位置的元素。
intIndexOf(Object o);
返回此列表中第一次出现该指定元素的索引;如果此列表不包含该元素,则返回-1.
intlastIndexof(Object o);
返回比列表中最后出现该指定元素的索引;如果列表中不包含此元素,则返回-1.
List<E>subList(int fromIndex,int toIndex);
返回列表中指定的fromIndex和toIndex之间的部分视图。
importjava.util.*; class ListDemo { public static void main(String[] args){ ArrayList<Person> coll= new ArrayList<Person>(); coll.add(new Person("王大",18)); coll.add(new Person("张三",20)); coll.add(new Person("王五",22)); coll.add(new Person("张三",20)); System.out.println(coll); //添加 coll.add(1,new Person("李二",19)); System.out.println(coll); //删除 System.out.println(coll.remove(1)); System.out.println(coll); //修改 System.out.println(coll.set(0,newPerson("李大",17)));//返回替换前的元素 System.out.println(coll); //获取 for(int i = 0; i <coll.size(); i++){ System.out.println(coll.get(i)); } System.out.println(coll.indexOf(newPerson("小明",18))); System.out.println(coll.indexOf(newPerson("张三",20))); System.out.println(coll.lastIndexOf(newPerson("张三",20))); System.out.println(coll.subList(1,3)); } }
import java.util.*; class ListIteratorDemo { public static voidmain(String[] args){ ArrayList<Person>coll = new ArrayList<Person>(); coll.add(newPerson("王大",18)); coll.add(newPerson("张三",20)); coll.add(newPerson("王五",22)); Iterator<Person>it = coll.iterator(); while(it.hasNext()){ Person p= it.next(); if(p.age== 20){ coll.add(newPerson("小明",23)); } System.out.println(p); } } }
如果在迭代器迭代的过程,集合操作列表元素,因为并发操作元素,这是会出现异常“ConcurrentModificationException”,这是需要Iterator的子接口ListIterator,该迭代器可以操作元素,只有List集合有。
import java.util.*; class ListIteratorDemo { public static voidmain(String[] args){ ArrayList<Person>coll = new ArrayList<Person>(); coll.add(newPerson("王大",18)); coll.add(newPerson("张三",20)); coll.add(newPerson("王五",22)); ListIterator<Person>it = coll.listIterator(); while(it.hasNext()){ Person p= it.next(); if(p.age== 20){ it.add(newPerson("小明",23)); } System.out.println(p); } } }
List常用子类:
--Vector:数组接口,查询慢,增删慢,因为同步。
--ArrayList:数组结构,查询快,增删慢,非同步。
--LinkedList:链表结合,增删快,查询慢,非同步。
链表
而链表的区间不连续,查询数据时,索引的时间比数组会长。但是如上图所示,增删是比数组快,因为数值增删需要整体位移。
Vector是jdk1.0是推出的集合容器,在2.0以后即被其它容器取代,不做介绍。
LinkedList在使用上具有差异性:链表存在头和尾,所谓含有特有的方法可以对链表头和尾的元素进行操作。
1、 添加。
void addFirst(E e);
将指定元素插入此列表的开头。
void addLast(E e);
将指定元素添加到此列表的结尾。
boolean offer(E e);
将指定元素添加到此列表的末尾。
boolean offerFirst(E e);
在此列表的开头插入指定的元素。
boolean offerLast(E e);
在此列表的末尾插入指定元素。
两者的区别:在使用双端队列且有容量限制的时候,offer方法在遇到容量过小时,返回false,而add则抛出异常,建议使用offer。
2、 修改
E removeFirst();
移除并返回此列表的第一个元素。
E removeLast();
移除并返回此列表的最后一个元素。
3、 获取
E getFirst();
返回此列表的第一个元素。
E getLast();
返回此列表的最后一个元素。
E peek();
获取但不移除此列表的头。
E peekFrist();
获取但不移除此列表的第一个元素;如果此列表为空,则返回null。
E peekLast();
获取但不移除此列表的最后一个元素;如果此列表为空,则返回null。
E poll();
获取并移除此列表的头。
E pollFrist();
获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
E pollLast();
获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
与remove的区别:当双端队列为空时remove抛出移除,而poll返回null。
import java.util.*; class LinkedListDemo { publicstatic void main(String[] args){ DuiLie<String>duiLie = new DuiLie<String>(); duiLie.add("123"); duiLie.add("456"); duiLie.add("789"); System.out.println(duiLie.size()); for(inti = 0;i < duiLie.size(); i++){ System.out.println(duiLie.get(i)); } DuiZhan<String>duiZhan= new DuiZhan<String>(); duiZhan.add("123"); duiZhan.add("456"); duiZhan.add("789"); System.out.println(duiZhan.size()); for(inti = 0;i < duiZhan.size(); i++){ System.out.println(duiZhan.get(i)); } } } class DuiLie<T> { privateLinkedList<T> coll ; DuiLie(){ coll= new LinkedList<T>(); } publicvoid add(T obj){ coll.add(obj); } publicT get(int index){ returncoll.get(index); } publicint size(){ returncoll.size(); } } class DuiZhan<T> { privateLinkedList<T> coll ; DuiZhan(){ coll= new LinkedList<T>(); } publicvoid add(T obj){ coll.addFirst(obj); } publicT get(int index){ returncoll.get(index); } publicint size(){ returncoll.size(); } }
上面已经介绍,需要注意的是在涉及到元素比较的方法,如contains、indexOf、retainAll、remove(Oject obj)时,默认调用的是元素的equals方法。
Set特点:无序,且不能重复的。
1、 Set集合怎么保证内部的元素是不重复的?
HashSet:首先比较元素的Hash码,即调用元素的hashCode()方法,如果不相同则元素不同;如果相同,则还需比较元素是否相同,即调用equals()方法,如果相同,则元素相同,不能装载,反之可以。
LinkedHashSet:同上。
TreeSet:调用元素的compareTo()方法或者是集合实现Comparator接口(优先compareTo()方法)。
2、 Set集合子类都有哪些?它们之间有什么区别?
--HashSet:无序,不重复。
--LinkedHashSet:有序,获取元素的顺序和存入一致。
--TreeSet:加载后的元素可以排序。
哈希表是一种算法,HashSet集合就是按hashCode返回的结果去存储和查询数据。比如我们去查找数元素时,首先拿到元素的hashCode值,然后去查找此hashcode对应的内存。
1、 为什么在jdk关于equlas方法的介绍时,建议equals相同时,hashcode也要相同?
因为部分集合HashSet、HashMap在添加元素时,调用equals的前提就是HashCode相同,如果equals()相同,反回来说明元素的HashCode一定是相同的。因为equals相同,而HashCode不同,存在的问题就是相同元素会添加到HashSet、HashMap中。
其实真正判读是否相同的依据还是equlas,只是从设计上来说,部分集合的逻辑是需要判断HashCode来存储数据的。
import java.util.*; class HashSetDemo { publicstatic void main(String[] args){ HashSet<Person>coll = new HashSet<Person>(); coll.add(newPerson("小强",25)); coll.add(newPerson("小明",23)); coll.add(newPerson("小张",24)); coll.add(newPerson("小张",24)); for(Iterator<Person>it = coll.iterator();it.hasNext();){ System.out.println(it.next()); } } } class Person { Stringname; intage; Person(Stringname,int age){ this.name= name; this.age= age; } publicString toString(){ returnname +":"+ age; } publicboolean equals(Object obj) { if(!(obj instanceof Person)) thrownew ClassCastException("不是Person类"); Personp = (Person)obj; returnname.equals(p.name) && age == p.age; } publicint hashCode(){ returnname.hashCode()+31*age; } }
特点:有序,hashSet的子类,就好像在hashSet基础上用一个链子根据元素存入的先后串联起来。
import java.util.*; class LinkedHashSetDemo { publicstatic void main(String[] args){ //HashSet<String>hs = new HashSet<String>(); LinkedHashSet<String>hs = new LinkedHashSet<String>(); hs.add("xixi"); hs.add("hehe"); hs.add("haha"); hs.add("88"); for(Iterator<String>it = hs.iterator();it.hasNext();){ System.out.println(it.next()); } } }
特点:可以按照元素排序。
1、 TreeSet是怎么实现元素排序的?
有两种方式:
第一种,元素需要实现comparable接口,复写compareTo方法,该方法比较两个元素,返回值为int,如果大于1,则顺序;等于0表示相等;小于0,则倒序。这又叫元素的自然排序。
importjava.util.*; classTreeSetDemo { public static void main(String[] args){ TreeSet<Person> ts = newTreeSet<Person>(); ts.add(new Person("小强",25)); ts.add(new Person("小明",23)); ts.add(new Person("小张",24)); ts.add(new Person("小李",23)); for(Iterator<Person> it =ts.iterator();it.hasNext();){ System.out.println(it.next()); } } } classPerson implements Comparable{ String name; int age; Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return name +":"+ age; } public boolean equals(Object obj){ if (!(obj instanceof Person)) throw newClassCastException("不是Person类"); Person p = (Person)obj; return name.equals(p.name) &&age == p.age; } public int hashCode(){ return name.hashCode()+31*age; } public int compareTo(Object obj){ /* if (obj.getClass() != Person){ throws newClassCastException("类型错误"); } */ //健壮性判断 if (!(obj instanceof Person)) throw newClassCastException("不是Person类"); Person p = (Person)obj; //return age - ((Person)obj).age; int temp = this.age - p.age; return temp == 0?this.name.compareTo(p.name):temp; } }
第二种,是集合实现Comparator接口,实现compare()方法,传入两个元素,比较大小,规则如上。
importjava.util.*; classTreeSetDemo { public static void main(String[] args){ TreeSet<Person> ts = newTreeSet<Person>(new MyComparator()); ts.add(new Person("小强",25)); ts.add(new Person("小明",23)); ts.add(new Person("小张",24)); ts.add(new Person("小李",23)); for(Iterator<Person> it =ts.iterator();it.hasNext();){ System.out.println(it.next()); } } } classPerson { String name; int age; Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return name +":"+ age; } public boolean equals(Object obj){ if (!(obj instanceof Person)) throw newClassCastException("不是Person类"); Person p = (Person)obj; return name.equals(p.name) &&age == p.age; } public int hashCode(){ return name.hashCode()+31*age; } } classMyComparator implements Comparator<Person> { public int compare(Person o1,Person o2){ int temp = o1.age -o2.age; return temp == 0? o1.name.compareTo(o2.name) : temp; } }
要点:集合自身的比较性优先于元素的比较性。
import java.util.*; class TreeSetTest { publicstatic void main(String[] args){ TreeSet<String>ts = new TreeSet<String>(new ComparatorByLength()); ts.add("abc"); ts.add("adcdef"); ts.add("ac"); ts.add("abcd"); for(Iterator<String>it = ts.iterator();it.hasNext();){ System.out.println(it.next()); } } } class ComparatorByLength implementsComparator<String> { publicint compare(String o1,String o2){ returno1.length() - o2.length(); } } import java.util.*; class TreeSetTest { publicstatic void main(String[] args){ TreeSet<String>ts = new TreeSet<String>(new ComparatorByLength()); ts.add("abc"); ts.add("adcdef"); ts.add("ac"); ts.add("ab"); ts.add("abcd"); for(Iterator<String>it = ts.iterator();it.hasNext();){ System.out.println(it.next()); } } } class ComparatorByLength implementsComparator<Object> { publicint compare(Object o1,Object o2){ Strings1 = (String)o1; Strings2 = (String)o2; inttemp = s1.length() - s2.length(); returntemp == 0? s1.compareTo(s2) : temp; } }
1、 Map集合的特点,与colllection的区别?
Map集合一次可以添加一对元素;collection一次添加一个元素。
Map称为双列集合;collection称为单列集合。
Map集合存放的是键值对,它们是映射关系,不能包含重复的键,一个键最多映射到一个值。
2、 有哪些常用方法?
1、 添加
V put(K key,V value);
返回前一个和key关联的值,如果没有则为null。
2、 删除
void clear();
清空Map集合。
V remove(K key);
根据键删除集合中的键值对。
3、 修改
4、 获取
V get(K key);
通过键获取值,如果没有该键,则返回null。
it size();
获取键值对的个数。
5、 判断
boolean containsKey(k key);
集合中是否包含该键。
boolean containsValue(V value);
集合中是否包含该值。
boolean isEmpty();
集合是否为空。
import java.util.*; class MapDemo { public static voidmain(String[] args){ //创建容器 HashMap<Integer,String>hm = new HashMap<Integer,String>(); //添加 hm.put(1,"abc"); hm.put(3,"efg"); hm.put(2,"hij"); hm.put(4,"小李"); System.out.println(hm); System.out.println(hm.put(2,"小明")); System.out.println(hm); //删除 hm.remove(4); System.out.println(hm); //判断 System.out.println(hm.containsKey(2)); System.out.println(hm.containsKey(4)); System.out.println(hm.containsValue("abd")); System.out.println(hm.containsValue("abc")); System.out.println(hm.containsValue(hm.isEmpty())); //获取 System.out.println(hm.size()); System.out.println(hm.get(1)); System.out.println(hm.get(4)); } }
1、 keySet()方法的介绍和使用?
Set<K> keyset();
返回此映射中所包含的键的Set视图。
获取到Set集合,然后通过迭代器的next()方法获取到每一个键值,再通过Map的get(K key)方法,根据每一个键获取到值。
import java.util.*; class KeySetDemo { publicstatic void main(String[] args) { //创建容器 HashMap<Integer,String>hm = new HashMap<Integer,String>(); //添加 hm.put(1,"abc"); hm.put(3,"efg"); hm.put(2,"hij"); hm.put(4,"小李"); //调用keySet()返回set集合 Set<Integer>set = hm.keySet(); //调用迭代器,遍历Set元素 for(Iterator<Integer>it = set.iterator();it.hasNext();){ Integerkey = it.next(); //通过Map的get(key)方法,再获取到值 Stringvalue = hm.get(key); System.out.println(key+":"+value); } } }
1、 entrySet()方法的介绍,与keySet()方法的区别?
Set<Map.Entry<K,V>>entrySet();
返回此映射所包含的映射关系的set视图。
与keySet()的区别:它返回的也是Set集合,但是集合中包含的元素却不是
由Map的key值组成,它是Map中key和value的映射关系,它是一个明确类型,类名为Map.Entry<k,v>,可以看出它是Map内部类,可以通过Set的迭代器来获取,在迭代过程中,它自身的方法可以获取key(getKey())和value(getValue()),也可以修改value值(setValue())。
Jdk中关于Map.Entry<k,v>的说明:映射项(键-值对)。Map.entrySet 方法返回映射的 collection 视图,其中的元素属于此类。获得映射项引用的唯一 方法是通过此 collection 视图的迭代器来实现。这些 Map.Entry 对象仅 在迭代期间有效;更确切地讲,如果在迭代器返回项之后修改了底层映射,则某些映射项的行为是不确定的,除了通过 setValue 在映射项上执行操作之外。
import java.util.*; class EntrySetDemo { public static voidmain(String[] args) { //创建容器 HashMap<Integer,String>hm = new HashMap<Integer,String>(); //添加 hm.put(1,"abc"); hm.put(3,"efg"); hm.put(2,"hij"); hm.put(4,"小李"); //调用keySet()返回set集合 Set<Map.Entry<Integer,String>>set = hm.entrySet(); //调用迭代器,遍历Set元素 for(Iterator<Map.Entry<Integer,String>>it = set.iterator();it.hasNext();){ Map.Entry<Integer,String>entry = it.next(); Integerkey = entry.getKey(); //修改 if(key==2) //hm.put(5,"++++++");迭代过程中集合不能操作元素 entry.setValue("======="); System.out.println(key+":"+entry.getValue()); } } }
1、 values()方法介绍?
Collection<V> values();
返回此映射所包含的值的Collection视图。
它可以看做是keySet()对应的方法;keySet()返回的是key值的集合,因为Map中key值不能重复,所以返回的是Set集合;而values()返回的是Map中value值的集合,因为value可以重复,所以返回集合为Collection;而entrySet()返回的是两者的关系。
import java.util.*; class ValuesDemo { public static voidmain(String[] args) { //创建容器 HashMap<Integer,String>hm = new HashMap<Integer,String>(); //添加 hm.put(1,"abc"); hm.put(3,"efg"); hm.put(2,"hij"); hm.put(4,"小李"); //调用valuest()返回Collection集合 Collection<String>values = hm.values(); //调用迭代器,遍历Collection元素 for(Iterator<String>it = values.iterator();it.hasNext();){ System.out.println(it.next()); } } }
1、 Map的常见子类对象及特点?
--HashTable:jdk1.0推出,内部结构哈希表,同步的,不允许null作为键,null作为值。
--Properties:用来存储键值对型配置文件的信息,可以和IO技术相集合。
--HashMap:内部结构是哈希表,不是同步的,允许null作为键,null作为值。
--TreeMap:内部结构是二叉树,不是同步的。
--LinkedHashMap:内部结构是链表,不是同步的。
不同Map容器在实际应用中,最大的区别就是可以对键值对不同的处理,比如HashMap会对键做是否相同的判断,即判断hashCode和equlas,和HashSet相同。
特点:HashMap会对键做是否相同的判断,即判断hashCode和equlas,和HashSet相同。
importjava.util.*; classHashMapDemo { public static void main(String[] main){ //创建容器,存放个人信息和所属城市 HashMap<Person,String>hm = new HashMap<Person,String>(); //添加 hm.put(new Person("小明",23),"上海"); hm.put(new Person("小李",22),"江苏"); hm.put(new Person("老王",44),"北京"); hm.put(new Person("小强",32),"浙江"); //修改 hm.put(new Person("小强",32),"海南"); //调用entrySet()返回set集合 Set<Map.Entry<Person,String>>entrySet = hm.entrySet(); //set迭代器 for(Iterator<Map.Entry<Person,String>>it = entrySet.iterator();it.hasNext();){ //获取set中元素 Map.Entry<Person,String>entry = it.next(); //获取key值 Person key =entry.getKey(); //获取value值 String value =entry.getValue(); System.out.println(key.name+":"+key.age+",地址:"+value); } } } class Person { String name; int age; Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return name +":"+age; } public boolean equals(Object obj){ if (!(obj instanceof Person)) throw newClassCastException("错误类型"); Person p = (Person)obj; return name.equals(p.name)&& age == p.age; } public int hashCode(){ return name.hashCode()+31*age; } }
特点:TreeMap会对键做大小判断,即元素中compareTo()方法的结果或者是TreeMap中Comparator接口compare()方法的结果,TreeMap相同。
import java.util.*; class TreeMapDemo { public static voidmain(String[] main){ //创建容器,存放个人信息和所属城市 TreeMap<Person,String>tm = new TreeMap<Person,String>(new MyComparator()); //添加 tm.put(newPerson("小明",23),"上海"); tm.put(newPerson("小李",22),"江苏"); tm.put(newPerson("老王",44),"北京"); tm.put(newPerson("小强",32),"浙江"); tm.put(newPerson("小强",19),"北京"); //调用entrySet()返回set集合 Set<Map.Entry<Person,String>>entrySet = tm.entrySet(); //set迭代器 for(Iterator<Map.Entry<Person,String>>it = entrySet.iterator();it.hasNext();){ //获取set中元素 Map.Entry<Person,String>entry = it.next(); //获取key值 Personkey = entry.getKey(); //获取value值 Stringvalue = entry.getValue(); System.out.println(key.name+":"+key.age+",地址:"+value); } } } class MyComparator implements Comparator<Person> { public intcompare(Person o1,Person o2){ int temp =o1.age -o2.age; return temp== 0? o1.name.compareTo(o2.name) : temp; } }
09-常用对象API(集合框架-Map集合-LinkedHashMap&关联源码).avi
特点:有序,获取键值对的顺序和添加顺序一致。
import java.util.*; class LinkedHashMapDemo { public static voidmain(String[] main){ //创建容器,存放个人信息和所属城市 //HashMap<Person,String>hm = new HashMap<Person,String>(); LinkedHashMap<Person,String>hm = new LinkedHashMap<Person,String>(); //添加 hm.put(newPerson("小明",23),"上海"); hm.put(newPerson("小李",22),"江苏"); hm.put(newPerson("老王",44),"北京"); hm.put(newPerson("小强",32),"浙江"); //调用entrySet()返回set集合 Set<Map.Entry<Person,String>>entrySet = hm.entrySet(); //set迭代器 for(Iterator<Map.Entry<Person,String>>it = entrySet.iterator();it.hasNext();){ //获取set中元素 Map.Entry<Person,String>entry = it.next(); //获取key值 Personkey = entry.getKey(); //获取value值 Stringvalue = entry.getValue(); System.out.println(key.name+":"+key.age+",地址:"+value); } } }
10-常用对象API(集合框架-Map集合练习-记录字母次数思路).avi
练习:字符串“fdgavcbsacdfs“获取字符串中,每一个字母出现的次数;要求打印的结果是:a(2)b(1)…..;
11-常用对象API(集合框架-Map集合练习-记录字母次数代码).avi
import java.util.*; class CharCountInString { public static voidmain(String[] main){ //待处理的字符串 String str ="fdgavcbsacdfs"; showCharCount(str); } public static voidshowCharCount(String s){ //首先需要遍历字符串每一个字符。放在数组中最好,当然也可以通过截取的方式。 //把字符串变成字符数组,便于遍历 char[] ch =s.toCharArray(); //创建Map集合,因为是从a开始的,所以是按键排序的,用TreeMap TreeMap<Character,Integer>tm = new TreeMap<Character,Integer>(); //for循环遍历 for(int i=0;i<ch.length; i++){ /*接着是处理逻辑,遍历字符是否出现过,出现:在这个字符后面计数+1,这让我们想到键值对的概率,所以需要一个Map集合*/ //把遍历到的每一个元素添加到Map中,但是Map的性质就是出现重复key,是直接用新的value值覆盖。 //所以添加要判断集合是否已经有该key值 charkey = ch[i]; if (tm.containsKey(key) ){ //如果有,则需要获取他的value值,value用来计数,需要在这个基础上+1, Integervalue = tm.get(key); value= value + 1; //把key和新的value值添加到集合中 tm.put(key,value); }else{ //如果没有,则value为初始值1 tm.put(key,1); } } //遍历结束,拿到Map集合,根据要求的打印形式,把键和值打印出来 Set<Map.Entry<Character,Integer>>entrySet = tm.entrySet(); for(Iterator<Map.Entry<Character,Integer>>it = entrySet.iterator();it.hasNext();){ Map.Entry<Character,Integer>entry = it.next(); Characterkey = entry.getKey(); Integervalue = entry.getValue(); System.out.print(key+"("+value+")"); } } }
12-常用对象API(集合框架-Map集合练习-Map查表法).avi
有映射关系,都可以用Map
标签:
原文地址:http://blog.csdn.net/qq_32736689/article/details/51865482