目录
一 集合框架
1.概述
2.集合的分类
3.数据结构
4.集合保证元素唯一性的方式
二 Collection 接口
1.常用方法
2.代码示例
3.迭代
三 List 接口
1.元素取出方式
2.特有方法
3.ListIterator
4.Vector 和 Enumeration
5.LinkedList
四 Set 接口
1.概述
2.HashSet
3.TreeSet
五 Map<k,v> 接口
1.概述
2.常见方法
3.元素取出方式
4. Entry
六 Collections 和 Arrays
1.Collection 和 Collections 的区别
2.Collections 常用方法
3.Arrays 常用方法
4.Arrays 特殊方法
注:本章重点内容:集合分类,数据结构,集合保证元素唯一性的方式,迭代,ListIterator,Enumeration<E>接口,List集合、Vector集合和Map集合的元素取出方式。对于重点内容,根据知识的重要程度用◆◆◆、◆◆◆◆、◆◆◆◆◆进行了标注。
####################################################################################
一 集合框架
####################################################################################
1.概述
(1)定义
集合框架,也叫集合体系、集合类。数据多了需要进行存储,封装成对象。对象多了也需要进行存储,要么数组,要么集合。
(2)为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
(3)数组和集合类同是容器,区别在哪里?
相同点:
集合和数组中存储的对象都是对象的引用(内存地址值)。
不同点:
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的;
数组只能存储同一种类型的对象,集合可以存储任意类型的对象;
数组中可以存储基本数据类型,集合只能存储对象;
(4)集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
◆◆◆◆◆【2.分类】◆◆◆◆◆
Collection 接口
|-- List (列表)接口。元素是有序的,元素可以重复。因为该集合体系有索引。
|-- ArrayList 底层是数组数据结构。线程不同步。特点:查询速度很快。增删稍慢。
|-- LinkedList 底层是链表数据结构。线程不同步。特点:增删速度很快,查询稍慢。
|-- Vector 底层是数组数据结构。线程同步。特点:增删查询速度慢,被ArrayList替代了。
|-- Set ( 集 )接口。 元素是无序的,元素不能重复。功能和 Collection 一致。 Set 底层使用了 Map 集合。
|-- HashSet 底层是哈希表数据结构。线程不同步。特点:存取速度快。
|-- TreeSet 底层是二叉树数据结构。线程不同步。特点:可以对set集合中的元素进行排序。
Map 接口
|--Hashtable 底层是哈希表数据结构,线程同步, 不可以存入 null 键和 null 值。jdk1.0.效率低。
|--Properties 属性集。线程同步,属性列表中每个键及其对应值都是一个字符串。
|--HashMap 底层是哈希表数据结构,线程不同步, 可以存入 null 值和 null 键,jdk1.2.效率高。将 Hashtable 替代。
|--TreeMap 底层是二叉树数据结构。线程不同步, 可以用于给 Map 集合中的键进行排序。
◆◆◆◆【3.数据结构】◆◆◆◆
定义:每一个集合都是一个容器,每一个容器对数据的存储方式都有不同。这个存储方式称之为数据结构。
哈希表数据结构:
哈希表是存放了一堆哈希值的表,将对象的哈希值存进去,顺序是按照哈希值来存的。和添加元素顺序可能不一致,取的时候也是按照哈希表里的顺序即哈希值来取的。
数组数据结构:
ArrayList 和 Vector 都是数组结构,数组结构特点在于它是固定长度的,而集合是可变长度的,即可变长度的数组。 ArrayList 默认长度为10的数组,当超过10个元素以后,再添加的话,就会再 new 一个新的数组,长度为50%延长,变为15,把原来数组中元素copy到新数组中来,再把新元素添加到后面去。 Vector 默认长度也为10,100%延长。
注意:
哈希算法的由来:若在一个集合中查找是否含有某个对象,通常是一个个的进行equals的比较,对象特别多时,效率很低,通过哈希算法,将集合分为若干个区域,每个对象算出一个哈希值,可将哈希值分组(一般模32为一组),每组对应某个存储区域,依一个对象的哈希码即可确定此对象对应区域,从而减少每个对象的比较,只需在指定区域查找即可,从而提高从集合中查找元素的效率。
◆◆◆◆◆【4.保证元素唯一性的方式】◆◆◆◆◆
数据结构不一样,保证元素唯一性的原理和方式也不一样。
(1)数组数据结构和链表数据结构保证元素唯一性是通过 equals 方法。
(2)哈希表数据结构保证元素唯一性是通过元素的 hashCode 和 equals 方法。当两种方法都存在时,以hashCode为主。如果元素的hashcode值不同,不会调用equals;如果元素的HashCode值相同,才会判断元素的equals方法是否为true。如果equals结果为 false,则在同一哈希值上存储两个对象。注意:对于判断元素是否存在,以及删除等操作,依赖的都是这样的方法。
(3)二叉树数据结构保证元素唯一性是通过 Comparable 接口中的compareTo和 Comparator 接口中的compare 方法,当两种方法都存在时,以compare为主。compareTo方法:让元素具备比较性,定义在 Comparable 接口中。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。compare方法:让集合具备比较性,定义在 Comparator 接口中。比较器。当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。在集合初始化时,就有了比较方式。定义一个类,实现Comparator接口,覆盖compare方法。
注意:
a.无序指的是存入和取出的顺序不一定一致
b.List集合判断元素是否相同,依据是元素的equals方法。ArrayList和LinkedList依赖的都是equals。
####################################################################################
二 Collection<E>集合
####################################################################################
Collection 是层次结构中的根接口。一个顶层接口,定义了集合框架的共性功能。
1.常用方法
1)添加
boolean add(E e) 添加一个元素。add方法的参数类型是 Object 。以便于接收任意类型对象。
boolean addAll(Collection<? extends E> c) 添加另一集合内所有元素
2)删除
boolean remove(Object o);删除一个元素
boolean removeAll(Collection<?> c)仅移除本集合中另一集合也有的元素,即移除本集合中与另一集合的交集
void clear();清空集合
3)判断。
boolean contains(Object o) 判断是否包含某个元素
boolean containsAll(Collection<?> c)判断是否包含另一集合中的所有元素
boolean isEmpty()判断集合是否为空 //其实它是在调用size方法
4)获取
Iterator<E> iterator()迭代。返回在此集合的元素上进行迭代的迭代器。
int size()获取集合长度
5)获取交集。
boolean retainAll(Collection<?> c)仅保留此集合中另一集合也有的元素,即保留本集合与另一集合的交集
6)集合变数组。
<T> T[] toArray(T[] a) 返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。此方法充当了基于数组的 API 与基于 collection 的 API 之间的桥梁。如果指定的数组能容纳该 collection,则返回包含此 collection 元素的数组。否则,将分配一个具有指定数组的运行时类型和此 collection 大小的新数组。如果指定的数组能容纳 collection,并有剩余空间(即数组的元素比 collection 的元素多),那么会将数组中紧接 collection 尾部的元素设置为 null。所以数组长度与集合长度刚刚好最合适。
◆◆◆◆◆【2.迭代】◆◆◆◆◆
迭代是取出集合中元素的一种方式。因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。每个集合都具备取出的方式,而这个方式不足以用一个方法来描述,所以把取出动作封装成一个对象。因为数据结构不同,每个取出对象中取出的实现方式也不一样。取出的方式就通过类被描述。
迭代器:
其实就是集合的取出元素的方式。如同抓娃娃游戏机中的夹子。集合中存放着元素,想要直接操作集合中的元素,在集合内部操作最方便。就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,所以取出方式定义成内部类。而每一个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容如判断和取出,可以将共性抽取。那么这些内部类都会符合一个规则,该规则是 Iterator 。通过集合对外提供的方法iterator()获取集合内部类的对象。
迭代中的方法:
E next() 返回迭代的下一个元素。
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
void remove() 从迭代器指向的 Collection 中移除迭代器返回的最后一个元素
注意:
a.迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration。迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。迭代器的next方法返回值类型是Object,所以要记得类型转换。
b.在迭代时循环中next调用一次,就要hasNext判断一次。next连续调用两次可能会访问到不存在的数值,发生 NoSuchElementException
####################################################################################
三 List 接口
####################################################################################
◆◆◆◆【1.取出LIst集合中元素的方式】◆◆◆◆
(1)E get(int index):通过角标获取元素。
(2)Iterator<E> iterator():通过迭代方法获取迭代器对象。
(3)ListIterator<E> listIterator() :通过列表迭代器获取迭代器对象
(4)通过高级for循环获取元素
2.List 接口特有方法
凡是可以操作角标的方法都是该体系特有的方法。
增
void add(int index,E element)在列表的指定位置插入指定元素
boolean addAll(int index, Collection<? extends E> c) 将指定 collection 中的所有元素都插入到列表中的指定位置
删
E remove(int index) 移除列表中指定位置的元素
改
E set(int index, E element) 用指定元素替换列表中指定位置的元素,返回以前在指定位置的元素
查
E get(int index) 返回列表中指定位置的元素
List<E> subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分列表
ListIterator<E> listIterator() 返回此列表元素的列表迭代器
ListIterator<E> listIterator(int index) 从列表的指定位置开始返回列表中元素的列表迭代器。
◆◆◆◆【3.ListIterator 】◆◆◆◆
(1)定义
List集合特有的迭代器。ListIterator是Iterator的子接口。相当于遍历过程中的增删改查。在迭代时,不可以通过集合对象的方法操作
集合中的元素,因为会发生 ConcurrentModificationException 异常。所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator
方法是有限的,只能对元素进行判断,取出,删除的操作,如果想要其它的操作如添加,修改等,就需要使用其子接口,ListIterator。
该接口只能通过List集合的listIterator方法获取。
(2)常用方法
Iterator 中的三个方法
E next() 返回迭代的下一个元素。
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素
ListIterator 中的方法
void add(E e) 将指定的元素插入列表(可选操作)。
E previous() 返回列表中的前一个元素。
boolean hasPrevious() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
void set(E e) 用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。
4.Vector 和 Enumeration
(1)特有方法
该类中所有带element的方法都是该类特有方法
Enumeration<E> elements() 返回此向量的组件的枚举。
◆◆◆◆【(2)Enumeration<E>接口 】◆◆◆◆
枚举中的方法:
boolean hasMoreElements() 测试此枚举是否包含更多的元素。
E nextElement() 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
枚举就是Vector特有的取出方式。
发现枚举和迭代器很像。其实枚举和迭代是一样的。因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。枚举郁郁而终了。
◆◆◆◆【(3)Vector 取出元素方式】◆◆◆◆
枚举
迭代器
列表迭代器
get方法,遍历for循环
高级for循环
5.LinkedList
(1)特有方法:
void addFirst(E e) 将指定元素插入此列表的开头。
void addLast(E e) 将指定元素添加到此列表的结尾。
E getFirst() 返回此列表的第一个元素。
E getLast() 返回此列表的最后一个元素。
获取元素,但不删除元素。如果集合中没有元素,会出现 NoSuchElementException
E removeFirst() 移除并返回此列表的第一个元素。
E removeLast() 移除并返回此列表的最后一个元素。
获取元素,但元素被删除。如果集合中没有元素,会出现 NoSuchElementException
(2)JDK1.6新特性
在JDK1.6出现了替代方法。
boolean offerFirst(E e);
boolean offerLast(E e);
E peekFirst();
E peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回 null 。
E pollFirst();
E pollLast();
获取元素,但是删除元素。如果集合中没有元素,会返回 null 。
代码示例
将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
1 import java.util.*; 2 //定义一个Person类 3 class Person 4 { 5 private String name; 6 private int age; 7 Person(String name,int age) 8 { 9 this.name = name; 10 this.age = age; 11 } 12 //这里的equals是复写Object类里的equals方法 13 public boolean equals(Object obj) 14 { 15 if(!(obj instanceof Person)) 16 return false; 17 Person p = (Person)obj; 18 //System.out.println(this.name+"....."+p.name); 19 //这里的equals是字符串的equals方法 20 return this.name.equals(p.name) && this.age == p.age; 21 } 22 public String getName() 23 { 24 return name; 25 } 26 public int getAge() 27 { 28 return age; 29 } 30 } 31 class ArrayListTest2 32 { 33 public static void sop(Object obj) 34 { 35 System.out.println(obj); 36 } 37 public static void main(String[] args) 38 { 39 ArrayList al = new ArrayList(); 40 //add方法添加的是object类型的对象。属于多态。al.add(Object obj);//Object obj = new Person("lisi01",30); 41 al.add(new Person("lisi01",30)); 42 al.add(new Person("lisi02",32)); 43 al.add(new Person("lisi02",32)); 44 al.add(new Person("lisi04",35)); 45 al.add(new Person("lisi03",33)); 46 al.add(new Person("lisi04",35)); 47 48 //调用去重复元素的方法 49 al = singleElement(al); 50 //remove方法底层也是依赖于元素的equals方法。先判断该元素是否存在,即与集合中元素比较是否相同,有的话再删除。 51 //sop("remove 03 :"+al.remove(new Person("lisi03",33))); 52 //对ArrayList集合进行迭代 53 Iterator it = al.iterator(); 54 while(it.hasNext()) 55 { 56 //Object obj=it.next(); 57 //Person p=(Person)obj: 58 //多态的向下转型 59 60 Person p = (Person)it.next(); 61 sop(p.getName()+"::"+p.getAge()); 62 } 63 } 64 65 public static ArrayList singleElement(ArrayList al) 66 { 67 //定义一个临时容器。 68 ArrayList newAl = new ArrayList(); 69 Iterator it = al.iterator(); 70 while(it.hasNext()) 71 { 72 Object obj = it.next(); 73 //contains方法底层也是依赖于元素的equals方法。判断该元素和集合中每个元素是否相同。 74 if(!newAl.contains(obj)) 75 newAl.add(obj); 76 } 77 return newAl; 78 } 79 }
####################################################################################
四 Set 接口
#####################################################################################
1.概述
Set 接口。元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。Set集合的功能和Collection是一致的。
Set 集合取出元素的方式只有迭代器。
2.HashSet
一般在开发时,只要描述这项事物,需要向集合中存时,一般都会复写hashCode和equals。需要描述当我们自定义对象的时候,定义一个对象,通常要复写 hashCode 和equals。因为有可能会存放在 HashSet 当中,如果不复写,也会有,但是是内存地址值contains方法和remove方法底层也都是依赖于元素的equals方法。contains方法是判断该元素和集合中每个元素是否相同。remove方法是先判断该元素是否存在,即与集合中元素比较是否相同,有的话再删除。
练习
往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。
1 import java.util.*; 2 class HashSetTest 3 { 4 public static void sop(Object obj) 5 { 6 System.out.println(obj); 7 } 8 public static void main(String[] args) 9 { 10 HashSet hs = new HashSet(); 11 //向HashSet集合中添加元素 12 hs.add(new Person("a1",11)); 13 hs.add(new Person("a2",12)); 14 hs.add(new Person("a3",13)); 15 hs.add(new Person("a2",12)); 16 //add方法添加的是object类型的对象。属于多态。al.add(Object obj);//Object obj = new Person("lisi01",30); 17 //sop("a2:"+hs.contains(new Person("a2",12))); 18 //hs.remove(new Person("a3",13)); 19 //对集合进行迭代 20 Iterator it = hs.iterator(); 21 while(it.hasNext()) 22 { 23 Person p = (Person)it.next(); 24 25 //Object obj=it.next(); 26 //Person p=(Person)obj: 27 //多态的向下转型 28 29 sop(p.getName()+"::"+p.getAge()); 30 } 31 } 32 } 33 //定义一个Person类 34 class Person 35 { 36 private String name; 37 private int age; 38 Person(String name,int age) 39 { 40 this.name = name; 41 this.age = age; 42 } 43 //覆盖hashCode方法 44 public int hashCode() 45 { 46 System.out.println(this.name+"....hashCode"); 47 //*37是防止两个对象的名字和年龄的和相同了,为了尽量保证哈希值的唯一性,也可以是随便别的数 48 return name.hashCode()+age*37; 49 } 50 //这里的equals是复写Object类里的equals方法 51 public boolean equals(Object obj) 52 { 53 if(!(obj instanceof Person)) 54 return false; 55 Person p = (Person)obj; 56 System.out.println(this.name+"...equals.."+p.name); 57 //这里的equals是字符串的equals方法 58 return this.name.equals(p.name) && this.age == p.age; 59 } 60 public String getName() 61 { 62 return name; 63 } 64 public int getAge() 65 { 66 return age; 67 } 68 }
3. TreeSet
二叉树/红黑树
需求:
往TreeSet集合中存储自定义对象学生。想按照学生的年龄进行排序。
记住,排序时,当主要条件相同时,一定判断一下次要条件。
1 import java.util.*; 2 class TreeSetDemo 3 { 4 public static void main(String[] args) 5 { 6 //定义一个TreeSet集合并添加元素 7 TreeSet ts = new TreeSet(); 8 9 ts.add(new Student("lisi02",22)); 10 ts.add(new Student("lisi007",20)); 11 ts.add(new Student("lisi09",19)); 12 ts.add(new Student("lisi08",19)); 13 //ts.add(new Student("lisi007",20)); 14 //ts.add(new Student("lisi01",40)); 15 //对集合进行迭代 16 Iterator it = ts.iterator(); 17 while(it.hasNext()) 18 { 19 Student stu = (Student)it.next(); 20 System.out.println(stu.getName()+"..."+stu.getAge()); 21 } 22 } 23 } 24 25 //定义一个Student类 26 class Student implements Comparable 27 //此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。 28 //该接口强制让学生具备比较性。如果没有该接口,当添加1个以上对象时会抛出 ClassCastException 异常。 29 lang.Comparable。 30 { 31 private String name; 32 private int age; 33 Student(String name,int age) 34 { 35 this.name = name; 36 this.age = age; 37 } 38 //覆盖compareTo方法 39 public int compareTo(Object obj) 40 { 41 //return 1;//可以按照添加顺序取出,原因是二叉树一直在向右下发展 42 //return -1;//可以倒序取出 43 //return 0;//只保留第一个元素 44 if(!(obj instanceof Student)) 45 throw new RuntimeException("不是学生对象"); 46 Student s = (Student)obj; 47 48 //System.out.println(this.name+"....compareto....."+s.name); 49 if(this.age>s.age) 50 return 1; 51 //当年龄相同时还要进一步判断其他属性 52 if(this.age==s.age) 53 { 54 55 return this.name.compareTo(s.name) 56 } 57 return -1; 58 } 59 public String getName() 60 { 61 return name; 62 } 63 public int getAge() 64 { 65 return age; 66 } 67 }
已知一个可以按照年龄对学生进行排序的类,在不改动学生类的情况下使其可以实现按照学生姓名进行排序的功能。
1 import java.util.*; 2 //定义一个学生类,默认实现按年龄排序。该接口强制让学生具备比较性。 3 class Student implements Comparable 4 { 5 private String name; 6 private int age; 7 8 Student(String name,int age) 9 { 10 this.name = name; 11 this.age = age; 12 } 13 public int compareTo(Object obj) 14 { 15 //return 0; 16 if(!(obj instanceof Student)) 17 throw new RuntimeException("不是学生对象"); 18 Student s = (Student)obj; 19 20 //System.out.println(this.name+"....compareto....."+s.name); 21 if(this.age>s.age) 22 return 1; 23 if(this.age==s.age) 24 { 25 return this.name.compareTo(s.name); 26 } 27 return -1; 28 } 29 public String getName() 30 { 31 return name; 32 } 33 public int getAge() 34 { 35 return age; 36 } 37 } 38 class TreeSetDemo2 39 { 40 public static void main(String[] args) 41 { 42 //定义一个TreeSet集合并添加元素 43 TreeSet ts = new TreeSet(new MyCompare()); 44 45 ts.add(new Student("lisi02",22)); 46 ts.add(new Student("lisi02",21)); 47 ts.add(new Student("lisi007",20)); 48 ts.add(new Student("lisi09",19)); 49 ts.add(new Student("lisi06",18)); 50 ts.add(new Student("lisi06",18)); 51 ts.add(new Student("lisi007",29)); 52 //ts.add(new Student("lisi007",20)); 53 //ts.add(new Student("lisi01",40)); 54 //对集合进行迭代 55 Iterator it = ts.iterator(); 56 while(it.hasNext()) 57 { 58 Student stu = (Student)it.next(); 59 System.out.println(stu.getName()+"..."+stu.getAge()); 60 } 61 } 62 } 63 //定义一个比较器 64 class MyCompare implements Comparator 65 { 66 //覆盖compare方法 67 public int compare(Object o1,Object o2) 68 { 69 Student s1 = (Student)o1; 70 Student s2 = (Student)o2; 71 72 int num = s1.getName().compareTo(s2.getName()); 73 //当姓名相同时,再判断一下其他属性 74 if(num==0) 75 { 76 return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); 77 /* 78 if(s1.getAge()>s2.getAge()) 79 return 1; 80 f(s1.getAge()==s2.getAge()) 81 return 0; 82 return -1; 83 */ 84 } 85 return num; 86 } 87 }
####################################################################################
五 Map <K,v> 接口
####################################################################################
1.概述
Map集合:
该集合存储键值对。一对一对往里存。而且要保证键的唯一性。Map集合的功能和Set集合很像,因为Set集合底层就是在调用Map集合。
什么时候使用 Map 集合?
当数据之间存在这映射关系时,就要先想 Map 集合。
Map与Collection的区别
Map与Collection在集合框架中属并列存在;
Map存储的是键值对;
Map存储元素使用put方法,Collection使用add方法;
Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素;
Map集合中键要保证唯一性;
2.常用方法
(1)添加。
V put(K key, V value) 返回这个键对应的原来的那个值。
当存入一个新的键值时返回null,当存入一个已有键和不同的值时,新值会替换原来的值。返回原来的值
void putAll(Map<? extends K,? extends V> m)
(2)删除。
void clear()
V remove(Object key)
(3)判断。
boolean containsValue(Object value)
boolean containsKey(Object key)
boolean isEmpty()
(4)获取。
V get(Object key)
int size()
Collection<V> values()
Set<K> keySet()
Set<Map.Entry<K,V>> entrySet()
◆◆◆◆【3.map集合的两种取出方式】◆◆◆◆
(1)Set<K> keySet:
将Map中所有的键存入到Set集合。因为Set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。
Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。
代码格式
TreeMap<K,V> tm=new TreeMap<K,V>();
tm.put(K key,V value);
……
Set<K> keySet=tm.keySet();
for (Iterator<K> it=keySet.iterator();it.hasNext() ; )
{
K key=it.next();
V value=tm.get(key);
……
}
(2)Set<Map.Entry<K,V>> entrySet:
Map.Entry<K,V> 接口,相当于 Collection 中的迭代器。将 Map 集合中的映射关系存入到了 Set 集合中,而这个关系的数据类型就是:Map.Entry。通过set集合的迭代方法可以获取到关系对象 Map.Entry。然后就可以通过 Map.Entry中的getKey和getValue方法获取关系中的键和值。
代码格式
TreeMap<K,V> tm=new TreeMap<K,V>();
tm.put(K key,V value);
……
Set<Map.Entry<K,V>> entrySet=tm.entrySet();
for (Iterator<Map.Entry<K,V>> it=entrySet.iterator();it.hasNext(); )
{
Map.Entry<K,V> me=it.next();
K key=me.getKey();
V value=me.getValue();
……
}
4. Entry
其实Entry也是一个接口,它是Map接口中的一个static内部接口。
为什么要定义在内部呢?
因为只有有了Map集合,有了键值对,才会有键值的映射关系。关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。
5.练习
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。希望打印结果:a(1)c(2).....
通过结果发现,每一个字母都有对应的次数。说明字母和次数之间都有映射关系。当发现有映射关系时,可以选择map集合。因为map集合中存放的就是映射关系。
思路:
1,将字符串转换成字符数组。因为要对每一个字母进行操作。
2,定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合。
3,遍历字符数组。将每一个字母作为键去查map集合。如果返回null,将该字母和1存入到map集合中。如果返回不是null,说明该字母在map集合已经存在并有对应次数。那么就获取该次数并进行自增。然后将该字母和自增后的次数存入到map集合中。覆盖原来的键所对应的值。例:abcabcdea第一次用字母a为键去找集合。那么集合没有a这个键,所以也没有对应的次数,返回null。如果为null,就将字母a和1存入集合;如果指定的键已经存在,说明有对应的次数。就将对应的次数取出,并且在自增后重新存入集合。
4,将map集合中的数据变成指定的字符串形式返回。
1 import java.util.*; 2 class MapTest3 3 { 4 public static void main(String[] args) 5 { 6 String s= charCount("ak+abAf1c,dCkaAbc-defa"); 7 System.out.println(s); 8 } 9 public static String charCount(String str) 10 { 11 //把字符串转成字符数组 12 char[] chs = str.toCharArray(); 13 //定义一个TreeMap集合 14 TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>(); 15 int count = 0; 16 //遍历数组,获取字符在集合中是否有值 17 for(int x=0; x<chs.length; x++) 18 { 19 if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z')) 20 //这句话可以滤除非字母的字符 21 continue; 22 //如果没有,把字符和1添加到集合,如果有则把值自增后放回集合 23 Integer value = tm.get(chs[x]); 24 if(value!=null) 25 count = value; 26 count++; 27 //直接往集合中存储字符和数字,为什么可以,因为自动装箱。 28 tm.put(chs[x],count); 29 count = 0; 30 } 31 //System.out.println(tm); 32 StringBuilder sb = new StringBuilder(); 33 //对集合迭代,并将数据用StringBuilder转成希望看到的形式 34 Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet(); 35 Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator(); 36 while(it.hasNext()) 37 { 38 Map.Entry<Character,Integer> me = it.next(); 39 Character ch = me.getKey(); 40 Integer value = me.getValue(); 41 sb.append(ch+"("+value+")"); 42 } 43 return sb.toString(); 44 } 45 }
####################################################################################
六 Collections 和 Arrays
####################################################################################
Collections:集合框架的工具类。里面定义的都是静态方法。
对集合进行查找
取出集合中的最大值,最小值
对List集合进行排序
Arrays: 操作数组的工具类。里面定义的都是静态方法。
将数组转成List集合
对数组进行排序
对数组进行二分查找
1.Collection 和 Collections 有什么区别?
Collection 是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。它有两个常用的子接口,List:对元素都有定义索引。有序的。可以重复元素。Set:不可以重复元素。无序。
Collections 是集合框架中的一个工具类。该类中的方法都是静态的。提供的方法中有可以对list集合进行排序,二分查找等方法。通常常用的集合都是线程不安全的。因为要提高效率。如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
2.Collections 常用方法
static <T> void fill(List<? super T> list, T obj) 使用指定元素替换指定列表中的所有元素。
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 根据元素的自然顺序,返回给定 collection 的最大元素。
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) 根据指定比较器产生的顺序,返回给定 collection 的最大元素。
static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) 使用另一个值替换列表中出现的所有某一指定值。
static void reverse(List<?> list) 反转指定列表中元素的顺序。
static <T> Comparator<T> reverseOrder() 返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。
static <T> Comparator<T> reverseOrder(Comparator<T> cmp) 返回一个比较器,它强行逆转指定比较器的顺序。
static void shuffle(List<?> list) 使用默认随机源对指定列表进行置换。
static <T extends Comparable<? super T>> void sort(List<T> list) 根据元素的自然顺序 对指定列表按升序进行排序。
static <T> void sort(List<T> list, Comparator<? super T> c) 根据指定比较器产生的顺序对指定列表进行排序。
static void swap(List<?> list, int i, int j) 在指定列表的指定位置处交换元素。
static <T> Collection<T> synchronizedCollection(Collection<T> c) 返回指定 Collection 支持的同步(线程安全的) Collection 。 List Map Set 也都有返回支持同步的方法。
3.Arrays 常用方法
static <T> List<T> asList(T... a) 返回一个受指定数组支持的固定大小的列表。
static boolean deepEquals(Object[] a1, Object[] a2) 如果两个指定数组彼此是深层相等 的,则返回 true。
static void sort(byte[] a)对指定 byte 型数组按数字升序进行排序。
static void sort(byte[] a, int start, int end) 对指定 byte 型数组的指定范围按数字升序进行排序。
static int binarySearch(byte[] a, byte key) 使用二分搜索法来搜索指定的 byte 型数组,以获得指定的值。
static int binarySearch(byte[] a,int start,int end,byte key) 使用二分搜索法来搜索指定的 byte 型数组的指定范围,以获得指定的值。
该方法重载,支持 byte short char int long float double Object 类型。
static String toString(boolean[] a) 返回指定数组内容的字符串表示形式。
static byte[] copyOfRange(byte[] bytes, int start, int end) 将指定数组的指定范围复制到一个新数组。
static void fill(boolean[] a, boolean val)将指定的 boolean 值分配给指定 boolean 型数组的每个元素。
static void fill(boolean[] a, int start, int end, boolean val) 将指定的 boolean 值分配给指定 boolean 型数组指定范围中的每个元素。
该方法重载,支持 boolean byte short char int long float double Object 类型。
4.Arrays 特殊方法
(1)数组变集合
static <T> List<T> asList(T... a)将数组变成list集合
把数组变成list集合有什么好处?
可以使用集合的思想和方法来操作数组中的元素。将数组变成集合后,不可以使用集合的增删方法。因为数组的长度是固定的。如果增删。会发生 UnsupportedOperationException,变成集合后可以使用的方法有:
boolean contains(Object o) 如果列表包含指定的元素,则返回 true。
E get(int index) 返回列表中指定位置的元素。
int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
List<E> subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
注意:
如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
(2)集合变数组。
Collection 接口中的toArray方法。
指定类型的数组到底要定义多长呢?
当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。当指定类型的数组长度大于了集合的size,就不会新创建数组。而是使用传递进来的数组。所以创建一个刚刚好的数组最优。
为什么要将集合变数组?
为了限定对元素的操作。不需要进行增删了。