一、集合框架
基于继承特征建立起的体系结构,集合框架相当庞大,首先看图解:
1、集合类出现的原因:
面向对象的核心就是对象,Java将所有的事物都封装成对象,我们要操作这些对象,就要将这些对象存储起来,而集合就是存储多个对象的容器。
2、集合类特点:
集合只用于存储对象。集合长度是可变的。集合可以存储不同类型的对象。
3、集合使用步骤:
1) 创建集合对象。
2) 创建元素对象。
3) 把元素对象添加到集合对象中。
4) 遍历集合对象(通过集合对象获取迭代器对象,通过迭代器对象的 hasNext()方法进行判断,通过迭代器对象的 next()进行获取)。
4、数组与集合类同是容器,有何区别?
1) 对象都使用集合存储;数据都使用数组存储。
2) 数组虽然也可以存储对象,但长度是固定的;集合长度是可变长度的。
3) 数组中存储的是同一类对象,还可以存储基本数据类型;集合只能存储对象。
4) 数组存储数据类型是固定的,而集合存储的数据类型不固定。
二、Collection接口
Collection 是层次结构中的根接口(顶层接口)。有两个常用的接口 List 和 Set。在 List接口中有常用类 ArrayList、LinkedList 和 Vector;在 Set 接口中有类 HashSet、TreeSet。
1、Collection子类:
List:元素有序,可以重复。(因为有索引)
Set:元素无序,不可以重复。
2、Collection中常见的操作:
添加:
boolean add(E e); //添加指定元素;接收的是一个 Object 类型对象。
boolean addAll(Collection<? extends E> c); //添加集合,一次添加一堆元素。
删除:
void clear( ); //清空容器。移除 Collection 中的所有元素(可操作)
boolean remove(Object o); //移除一个指定元素
boolean removeAll(Collection<? > c); //移除一堆元素。只要有元素被删除,就返回 true。
获取:
int size(); //获取集合长度,若为 0,则为空,没有元素。
判断:
boolean isEmpty(); //若不包含元素,返回 ture。
boolean contains(); //包含指定元素,返回 ture。判断是否含有某个元素。
boolean containsAll(Collection c); //判断是否含有指定集合中的所有元素,只有所有数据都包含才返回 true
其他:
int hashCode( ); //返回此 collection 的哈希码值
Iterator <E> iterator( ); //返回此元素上进行的迭代器,用于遍历集合中的元素
boolean retainAll( ); //取交集。只在调用者中保留共同的交集元素。
3、迭代器:
1)概念:
其实就是集合取出元素的方式,将取出方式定义在集合内部,这样取出方式就可以直接访问集合内部的元素。那么取出方式就定义为了内部类,而根据每个数据结构的不同,去除取出方式也不同,但都有共性内容:判断和取出,那么久抽取出共性内容,将其封装成对象Iterator。 集合都可以使用iterator()方法获取取出对象Iterator。
2)迭代器的常见操作:
hasNext(); //有下一个元素,返回真
next(); //取出下一个元素
remove(); //移除
Note:在迭代时循环中next调用一次,就要hasNext判断一次。
以下代码演示迭代器的使用:
public class CollectionDemo {
public static void main(String[] args) {
method_3();
}
public static void method_3() {
// 创建一个集合容器,使用Collection接口的子类---ArrayList
ArrayList al1 = new ArrayList();
// 添加元素
al1.add("demo1");
al1.add("demo2");
al1.add("demo5");
al1.add("demo6");
//获取迭代器,第一种方法
Iterator it1 = al1.iterator();
while (it1.hasNext()) {
System.out.println("while::"+it1.next());
}
//for循环,迭代器对象随着循环结束而消失,内存开销小,第二种方法
for (Iterator it = al1.iterator(); it.hasNext();) {
System.out.println("for::"+it.next());
}
}
}
结果如图所示:
迭代注意事项:
1) 迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
2) 迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
3) 迭代器的next方法返回值类型是Object,所以要记得类型转换。
三、List
1、List:元素是有序的,元素可以重复。因为该集合体系有索引。
2、List 接口中的特有方法:
add(int index,Object obj); //在指定位置加入元素
remove(int index); //移除指定位置的元素
set(int index,Object obj) ; //修改指定位置的元素
get(int index) ; //获取指定位置的元素
indexOf(Object obj) ; //获取指定元素的位置
subList(int start,int end) ; //从一个大的 List 中截取一个小的 List
3、List 特有迭代器:
ListIterator<E> listIterator( ); //返回列表迭代器。
ListIterator 是 Itertorde 子接口。 在迭代时,不可以通过集合对象的方法操作集合中的元素,容易发生安全隐患;报错:并发修改异常 ConcurrentModificationException。在迭代器时,只能用迭代器的方法操作元素,可是 Iterator 方法是有限的,只能对元素进行判断、取出、删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过 List 集合的 listIterator 方法获取。
示例如下:
import java.util.ArrayList;
import java.util.ListIterator;
/*
* List集合特有的迭代器ListIterator是Iterator的子接口
* 在迭代时,不可以通过集合对象的方法来操作集合中的元素,因为会发生并发修改异常
*/
public class CollectionSub {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
ListIterator li = al.listIterator();
while (li.hasNext()) {
Object obj = li.next();
if (obj.equals("java02")) {
li.set("java009");
}
}
System.out.println(al);
System.out.println("hasNext?" + li.hasNext());
System.out.println("hasPrevious?" + li.hasPrevious());
}
}
4、常见子类对象:
ArrayList:底层的数据结构是数组结构,查询快,增删慢,线程不同步(长度初始值为10,增量50%)
LinkedList:底层是链表结构,增删快,查询慢
Vector:底层是数组数据结构,线程同步,被ArrayList所取代,(长度初始值为10,增量100%)
1)ArrayList
特有方法: (凡是可以操作角标的方法都是该体系特有的方法)
添加:
void add(int index , E element); //在指定位置插入指定元素。
boolean addAll(int index ,Collection<? extends E> c); //将所有元素插入到列表中指定位置。
删除:
remove(int index); //移除指定位置上的元素
修改:
set(int index, E element); //修改指定索引值上的元素
查询:
get(int index); // 获取位置索引
int indexOf (Object o); //判断位置索引。如果不含该元素,则返回-1.
subList(int fromIndex ,int toIndex); //截取。含头不含尾。
boolean hasPrevious( ); //如果以逆向遍历列表,列表迭代器有多个元素,则返回 true
2)Vector
特有方法:
void addElement(); //添加组件
elementAt(int index); //相当于 get 方法
firstElement(); //获取第一个组件
insertElement(E obj , int index); //插入
last Element(); //最后一个组件
removeAllElements(); //移除
public Enumeration elements(); //返回此向量的组件枚举
枚举就是 Vector 特有的取出方式。枚举和迭代是一样的,但枚举的名称和方法的名称都过长,所以就被迭代器取代了。
枚举 Enumeration 的方法摘要:
boolean hasMoreElements(): 测试此枚举是否包含更多的元素。
E nextElement(): 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
Enumeration 是一个接口,此接口的功能与 Iterator 接口的功能是重复的。 此外, Iterator接口添加了一个移除操作,并使用较短的方法名。新的实现应该优先考虑 Iterator 接口,而不是 Enumeration 接口。
示例如下:
/*
* Vector特有的去除方式--枚举Enumeration
* 枚举和迭代都是一样的
*/
import java.util.Enumeration;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
Vector v = new Vector<>();
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");
Enumeration en = v.elements();
while (en.hasMoreElements()) {
System.out.println(en.nextElement());
}
}
}
3)LinkedList
特有方法:
void addFirst( ); //在此列表的开头插入指定的元素。
void addLast( );
getFirst(); //获取元素,但不删除元素
getLast();
removeFirst(); //获取元素,但删除元素,容量减少
removeLast(); //当集合中没有元素时,使用上面的方法会出现没有这个元素异常NoSuchElementException
JDK1.6 版本出现下面代替方法:
boolean offerFirst(); //在此列表的开头插入指定的元素。
boolean offerLast(); //在此列表末尾插入指定的元素。
peekFirst(); // 获取元素,但不删除元素。如果集合中没有元素,会返回 null。
peekLast();
pollFirst(); // 获取元素,但是元素被删除。如果集合中没有元素,会返回 null。
pollLast();
演示如下:
import java.util.LinkedList;
/*
* LinkedList特有方法演示:
*/
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList ll = new LinkedList();
ll.addFirst("java01");
ll.addLast("java01");
ll.addLast("java02");
ll.addLast("java03");
ll.addLast("java04");
System.out.println(ll.removeFirst());
System.out.println(ll.getLast());
System.out.println("长度:" + ll.size());
while (!ll.isEmpty()) {
System.out.println(ll.pollFirst());
}
}
}
四、Set
1、概述:
Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。Set 继承一个不包含重复元素的 Collection。Set 集合的功能和 Collection 是一致的。特点:唯一、无序、不重复。
HashSet: 底层数据结构是哈希表。元素唯一、线程不安全,非同步。但效率高。允许使用 null。元素。不保证迭代顺序,特别是它不保证该顺序恒久不变。
TreeSet: 底层数据结构是二叉树。可以对 Set 集合中的元素进行排序。
2、HashSet
HashSet:数据结构是哈希表,线程是非同步。
哈希表:根据哈希算法存储的,存储的就是对象的哈希值。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
保证元素唯一性的原理:判断元素的 hashCode 值是否相同。若相同,会继续判断元素的 equals 方法,是否为 true。
示例如下:
import java.util.HashSet;
import java.util.Iterator;
/*
* HashSet:
* HashSet 中的 add 方法都做了什么?
* 添加集合元素,同时会调用 hashCode 方法,在内存中形成对象的哈希值。
* HashSet 中特有的 add 方法 (add 的返回值是 boolean 类型的) 自动调用 equals 方法:
* 首先判断元素的 hashCode 值是否相同。若不同,直接添加元素。若相同,会继续判断
* 元素的 equals 方法,元素相同返回 false,不添加元素;元素不同,返回 true,添加元素。
* Tips:对于判断元素是否存在以及删除等操作,都是依赖于hashCode和equals方法
*/
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
System.out.println(this.name + "...hashCode");
return name.hashCode() + age * 39;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person)) {
return false;
}
Person p = (Person) obj;
System.out.println(this.name + "...equals..." + this.age);
return this.name.equals(p.getName()) && this.age == p.getAge();
}
}
public class SetDefine {
public static void main(String[] args) {
HashSet hs = new HashSet<>();
hs.add(new Person("zhangsan", 12));
hs.add(new Person("li", 15));
hs.add(new Person("li", 15));
hs.add(new Person("wangwu", 23));
hs.add(new Person("zhaoliu", 25));
System.out.println(hs.contains(new Person("li", 15)));
System.out.println(hs.remove(new Person("li", 15)));
Iterator it = hs.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
结果如图所示: 2)TreeSet
特点:
1) 底层的数据结构为二叉树结构(红黑树结构)
2) 可对Set集合中的元素进行排序,是因为:TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,需要复写compareTo方法,才能让对象按指定需求(如人的年龄大小比较等)进行排序,并加入集合。
Note:排序时。当主要条件相同时,一定要判断一下次要条件。
Comparable:此接口强行对实现它的每个类的对象进行整体自然排序,使元素具备比较性
Comparator:强行对某个对象 collection 进行整体排序的比较函数,使集合具备比较性
TreeSet 排序的第一种方式:
让元素(集合)自身具备比较性。元素需要实现 Comparable 接口,覆盖 compareTo 方法。这种方式也成为元素的自然顺序,或者叫做默认顺序。基本数据类型或字符串对象均实现了 Comparable 接口,故同种类型基本数据间具备比较性,即自然顺序。
TreeSet 排序的第二种方式:
当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。定义比较器,将比较器对象作为参数传递给TreeSet 构造函数。在集合初始化时,就有了比较方式。利用 TreeSet(Comparator Comparator); 构造方法构造一个新的空 TreeSet,它根据指定比较器进行排序。Comparator 是一个接口,接口中有两个方法:
int compare(T o1,T o2); //比较用来排序的两个参数。
Boolean equals(Object o); //指示某个其他对象是否等于此“Comparetor”。
Note:当两种排序都存在时,以比较器为主。
示例如下:
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*
* TeeSet:可以对Set集合的元素排序
* 底层的数据结构是二叉树保证元素的唯一性,依赖于compareTo方法
* 排序方式:
* 1、让元素自身具备比较性,元素需要实现Comparable接口覆盖compareTo方法,完成自然排序的默认顺序
* 2、当元素自身不具备比较性或者具备的比较性并非所需要的,此时要让集合自身具备比较性.定义比较器,将比较器对象作为参数传递给TreeSet构造函数。
* 两种方法排序是以比较器为主
*/
class Student implements Comparable { // 强制让学生具备比较性
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
if (!(o instanceof Student)) {
throw new RuntimeException("不是学生对象!!!");
}
Student stu = (Student) o;
return (this.age - stu.getAge()) == 0 ? this.name.compareTo(stu
.getName()) : (this.age - stu.getAge());
}
}
// 比较器
class myComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
Student stu1 = (Student) o1;
Student stu2 = (Student) o2;
int nameOff = stu1.getName().compareTo(stu2.getName());
return nameOff == 0 ? stu1.getAge() - stu2.getAge() : nameOff;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet t = new TreeSet(new myComparator());
t.add(new Student("zhangsan", 24));
t.add(new Student("li", 23));
t.add(new Student("wangwu", 23));
t.add(new Student("zhaoliu", 23));
t.add(new Student("zhaoliu", 25));
Iterator it = t.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
结果如下所示:
五、Map<K,V>接口
1、Map 集合: 该集合存储键值对,成对存入,保证键的唯一性。map 将键映射到值的对象。键值对之间用等号(=)连接。Map 和 Set 很像,Set 集合底层就是使用了 Map 集合。(K: 代表此映射所维护的键的类型 V: 代表映射值的类型)
2、Map集合子类:
|--Hashtable 底层是哈希表结构,不可以存入null键null值,线程是同步的
|--HashMap 底层是哈希表结构,允许使用null键null值,线程不同步效率高
|--TreeMap 底层是二叉树结构,线程不同步,可以用于给map集合中的键进行排序
3、Map集合常用方法:
添加:
V put(K key, V value); //将指定的值与此映射中的指定键关联
Note:当 key 在集合中不存在时,添加元素;当 key 在集合存在的时,替换元素。即若添加时出现相同的键,那么新添加的值会覆盖原有的键对应值,并且 put 方法会返回所被覆盖的值。
删除:
clear(); //移除所有键值对数据
V remove(Object key); // 移除;根据指定键删除键值对。
Note: 当不存在该键时,返回值为 null;若存在该键, 则删除该键,并返回该键所对应的值。
判断:
boolean containsValue(Object value);//判断指定值是否在集合中存在,若此映射将一个或多个键映射到指定值返回true。
boolean containsKey(); //判断指定键是否在集合中存在。若此映射包含指定键的映射关系,则返回 true。
boolean isEmpty(); //判断集合是否为空。若此映射未包含键、值映射关系,则返回 true。
获取:
Collection<V> values();//获取 map 集合中所有的值。获取元素值,V 代表键值类型
V get(Object key); //根据键获取值。返回指定键所在的值,若不存在该键,则返回 null。
Note:可以通过 get()方法的返回值来判断一个键是否存在。通过返回 null 来判断。
void putAll(); //从指定映射中将所有映射关系复制到此映射中
int size(); // 获取长度
演示如下:
import java.util.HashMap;
import java.util.Map;
/*
* Map:存储的是键值对,并且保证了键的唯一性
* 1、添加元素
* put()
* putAll()
* 2、删除元素
* clear()
* remove()
* 3、判断
* boolean containsKey()
* boolean containsValue()
* 4、获取
* get()
* size()
* values()
*
* Map:
* |--Hashtable 底层是哈希表结构,不可以存入null键null值,线程是同步的
* |--HashMap 底层是哈希表结构,允许使用null键null值,线程不同步效率高
* |--TreeMap 底层是二叉树结构,线程不同步,可以用于给map集合中的键进行排序
*/
public class MapDemo1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String, String> map = new HashMap<String, String>();
// 添加元素是如果出现相同的键,那么后添加的值会覆盖原有键对应的值,并且put方法会返回被覆盖的值
map.put("001", "zhangsan1");
System.out.println(map.put("001", "lisi"));
map.put("002", "zhangsan2");
map.put("003", "zhangsan3");
System.out.println("containsKey---" + map.containsKey("002"));
// System.out.println("remove---" + map.remove("003"));
// 可以通过get方法的返回值来判断一个键是否存在
map.put("004", "not null");
System.out.println("get---" + map.get(null));
// 获取map集合中所有的值,返回值Collections
System.out.println("values---" + map.values());
System.out.println(map);
}
}
结果如图所示:
4、Map集合元素的获取:
因为Map中没有迭代器,所以只能先用自有方法将元素转移到有迭代器集合中再逐个迭代取出。此处有两种方法:
1)Set<k> keyset() //返回所有键的集合。
原理:将 map 集合转成 set 集合,再通过迭代器取出。返回此映射中包含的键的 Set 视图;也就是将 map 中的所有键都存到 Set 集合中。因为:set 具备迭代器。所以可以通过迭代方式取出所有的键,再根据 get()方法获取每一个键所对应的值。
步骤:
a) 先获取 map 集合的所有键的 Set 集合,通过 keySet()方法;
b) 获取迭代器,取得 map 所有键。然后通过 map 集合的 get()方法获取元素对象的值。
2)set<Map.Entry<K,V>> entrySet() //键值对对象的结合。返回此映射中包含的映射关系的 Set 视图。
原理:将 Map 集合中的映射关系存入到 Set 集合中。这个映射关系的数据类型是Map.entry,再通过 Map.Entry 类的方法再要取出关系里面的键和值,Map.Entry<K,V>是一个静态接口,可以理解为一种映射关系。
Note:Map.Entry<K,V>是一个静态接口,可以理解为一种映射关系。Map.Entry 被封闭在 Map 接口中。其实 Entry 也是一个接口,代表一种映射关系。Entry 是 Map 接口中的一个内部接口。Map.Entry<K,V>中有以下方法:
boolean equals(); //比较指定对象与此项的相等性
getKey(); //返回与此项对应的键
getValue(); //返回与此项对应的值
int hashCode(); //返回此映像的哈希码值
setValue(value); //用指定的值替换对应的值
3)步骤:
a) 将 Map 集合中的映射关系取出,存入 Set 集合中。
b) 通过 Map.Entry 类的方法再要取出关系里面的键和值
两种元素取出方式演示如下:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
* Map键值对取出方式:
* 1、keySet:
* 将map中所有的键存入Set集合中,因为Set集合有迭代器,利用迭代器取出key在利用map的get()方法获取键对应的值
* 2、Set<Map.Entry<k,v>> entrySet:
* 将Map集合中的映射关系取出存入到Set集合中,再利用Set的迭代器获取键值对
*
*/
public class MapDemo2 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("01", "zhangsan1");
map.put("02", "zhangsan2");
map.put("03", "zhangsan3");
map.put("04", "zhangsan4");
System.out.println("第一种方式取出");
Set<String> mapSet = map.keySet();
Iterator<String> itSet = mapSet.iterator();
while (itSet.hasNext()) {
String key = itSet.next();
System.out.println(key + "--itSet--" + map.get(key));
}
System.out.println("第二种方式取出");
Set<Map.Entry<String, String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> itEntrySet = entrySet.iterator();
while (itEntrySet.hasNext()) {
Map.Entry<String, String> me = itEntrySet.next();
System.out.println(me.getKey() + "--itEntrySet--" + me.getValue());
}
}
}
结果如下所示: 4、Map集合的拓展及应用:
1)Hashtable: 底层是哈希表的数据结构,不可以存入 null 键 null 值。线程同步。
此类实现一个哈希表,该哈希表将键映射到相应的值。 任何非 null 对象都可以用作键或值。 在哈希表中存储和获取对象, 用作键的对象必须实现 hashCode()方法和 equals()方法(以能保证键的唯一性)。
2)HashMap: 基于哈希表的 map 接口实现,底层是哈希表的数据结构,并允许使用 null值、null 键,该集合线程不同步、无序。
保证元素唯一性的原理: 先判断元素的 hashCode 值是否相同,再判断两元素的 equals方法是否为true(往 HashSet 里面存的自定义元素要复写 hashCode 和 equals 方法,以保证元素的唯一性)。
3)TreeMap: 底层是二叉树数据结构。线程不同步,可以用于给 map 集合中的键进行排序,其实 Set 底层就使用了 Map 集合。
应用实例如下:
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/*
* "asdadgaadgfgjnknckjnfvcxvergccxk"获取字符串中的自摸出项的次数
* 打印结果为:a(2) b(3) ...
*
* 1、将字符串转换成字符数组
* 2、定义一个Map集合
* 3、遍历字符数组。
* 将每一个元素作为键去查Map集合
* 如果返回值为null,将该子母和1存入到Map中
* 如果返回不是null,则说明该字母出现过,将该字母对应的值自增1再存入Map中
* 4、按照指定格式打印出来
*/
public class MapTest3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str = "asdadgaadgf--===gjnknckjnfvcxvergccxk";
String result = charCount(str);
System.out.println(result);
}
public static String charCount(String str) {
//将字符串变成字符数组
char[] chs = str.toCharArray();
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
int count = 0;//定义计数器
for (int i = 0; i < chs.length; i++) {
//剔除非字母字符
if (!(chs[i] >= 'a' && chs[i] <= 'z' || chs[i] >= 'A'
&& chs[i] <= 'Z')) {
continue;
}
Integer value = tm.get(chs[i]);
if (value != null) {
count = value;
}
count++;
tm.put(chs[i], count);
count = 0;//每次循环后都将计数器置为零
/*
* if (value == null) { tm.put(chs[i], 1); } else { tm.put(chs[i],
* ++value); }
*/
}
// System.out.println(tm);
//定于StringBuilder存放结果
StringBuilder sb = new StringBuilder();
Set<Map.Entry<Character, Integer>> entrySet = tm.entrySet();
Iterator<Map.Entry<Character, Integer>> it = entrySet.iterator();
while (it.hasNext()) {
Map.Entry<Character, Integer> me = it.next();
Character ch = me.getKey();
Integer in = me.getValue();
sb.append(ch + "(" + in + ")");
}
return sb.toString();
}
}
结果如下所示:
六、工具类
1、Collections: 集合框架的工具类。里面定义的都是静态方法。
Collections 和 Collection 有什么区别?
Collection: 是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。它有两个常用的子接口,List:对元素都有定义索引。有序的。可以重复元素。Set:不可以重复元素。无序。
Collections: 是集合框架中的一个工具类。该类中的方法都是静态的。此类完全由在 collection上进行操作或返回 collection 的静态方法组成。提供的方法中有可以对 list 集合进行排序,二分查找等方法。通常常用的集合都是线程不安全的。因为要提高效率。如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
特点:方法都是静态的,不需要创建对象。
public static <T extends Comparable <? Super T>> void sort(List<T> list) //排序。
max(); //返回最大元素
binarySearch(); //二分法查找,前提必须是有序集合。
fill(); //可以将 list 集合中所有元素替换成指定元素。 也可以将 list 集合中部分元素替换成指定元素。
replaceAll(); //替换,按元素替换
reverse(); //反转
reverseOrder(); //反向排序,可以强行逆转比较器
swap(); //置换
shuffle(); //随机排序
集合有一个共同的缺点,那就是线程不安全,被多线程操作时,容易出现问题,虽然可以自己加锁,但是麻烦。Collections 提供特牛的方法,就是给它一个不同步的集合,它返回一个同步的安全的集合。
synchronizdMap(); //返回指定列表支持的同步(线程安全的)映射。
synchronizdList(); //返回指定列表支持的同步(线程安全的)列表。
synchronizedSet(); //返回指定列表支持的同步(线程安全的)集合Set。
示例如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
/*
* 集合框架工具类:
* Collections:所有的方法都是静态的
* 1、排序方法:
* static <T extends Comparator<? super T>> void sort(List<T> list)
* staitc void sort(List<T> list,Comparator<? super T> com)
*/
class StringLngthComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
return o1.length() - o2.length() == 0 ? o1.compareTo(o2) : o1.length()
- o2.length();
}
}
public class CollectionsDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("ijk");
list.add("abcabc");
list.add("fgh");
list.add("cdef");
list.add("lmn");
Collections.sort(list, new StringLngthComparator());
System.out.println(list);
sortDemo(list);
maxDemo(list);
// 练习:将list集合中部分元素替换成指定元素
fillDemo(list, "aa");
replaceDemo(list, "fgh", "fff");
System.out.println(list);
reverseOrderDemo();
shuffleDemo();
}
private static void shuffleDemo() {
List<String> shu = new ArrayList<String>();
shu.add("a");
shu.add("ab");
shu.add("fgh");
shu.add("cdef");
shu.add("zzzzzz");
System.out.println(shu);
Collections.shuffle(shu);
System.out.println(shu);
}
public static void reverseOrderDemo() {
TreeSet<String> set = new TreeSet<String>(Collections.reverseOrder());
set.add("a");
set.add("ab");
set.add("fgh");
set.add("cdef");
set.add("zzzzzz");
System.out.println(set);
}
public static void replaceDemo(List<String> list, String oldString,
String newString) {
Collections.replaceAll(list, oldString, newString);
}
public static void fillDemo(List<String> list, String str) {
Collections.fill(list, str);
}
public static void maxDemo(List<String> list) {
System.out.println("Max="
+ Collections.max(list, new StringLngthComparator()));
}
public static void sortDemo(List<String> list) {
System.out.println(list);
Collections.sort(list, new StringLngthComparator());
System.out.println(list);
}
}
2、Arrays: 用于操作数组的工具类,里面都是静态方法。
Lsit<T> asList(T... a) //将数组变成 list 集合,可以使用集合的思想和方法来操作数组中的元素。
copyOfRange(); //将指定数组复制到新的数组。
equals(); //比较数组元素是否完全相同
deepEquals(); //比较数组元素,并且比较元素内容是否相同。
fill(); //替换数组中的元素,还可以替换数组中的范围。
sort(); //排序
toString(); //转化成字符形式
Note:
a)将数组变成集合,不可以使用集合的增删方法。否则会发生不支持操作异常(UnsupportedOperationException)。
b)如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
c)如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
示例如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/*
* Arrays:
*
* 数组变集合
* asList(T... a)
* 1、将数组变成集合目的是便于使用集合的方法操作,但是不能增删否则会出现UnsupportionException
* 2、如果数组中的元素都是对象,则直接转成集合中的元素
* 3、如果数组中的元素都是基本数据类型,那么回将数组作为集合中的元素
*
* 集合变数组
* toArray()
*/
public class ArraysDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
asListDemo();
toArrayDemo();
}
private static void toArrayDemo() {
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
al.add("abc4");
/*
* 1、指定类型的数组初始长度: -- 当指定数组的长度小于了集合的长度,那么方法内部会重新创建一个新的数组长度和集合一样
* 当指定的数组长度大于集合的长度,那么就直接使用传递进来的数组 2、为什么将集合变数组:-- 为了限定对集合元素的操作
*/
String[] arr = al.toArray(new String[5]);
System.out.println(Arrays.toString(arr));
}
public static void asListDemo() {
String[] arr = { "abc", "efg", "xyz" };
int[] ar = { 1, 2, 3 };
List<String> listStr = Arrays.asList(arr);
System.out.println("Contains---" + listStr.contains("abc"));
List<int[]> list = Arrays.asList(ar);
System.out.println(list);
}
}
本篇幅所描述的仅代表个人看法,如有出入请见谅。