------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1. 集合
---|Collection: 单列集合 ---|List: 有存储顺序, 可重复 ---|ArrayList: 数组实现, 查找快, 增删慢 由于是数组实现, 在增和删的时候会牵扯到数组 增容, 以及拷贝元素. 所以慢。数组是可以直接 按索引查找, 所以查找时较快 ---|LinkedList: 链表实现, 增删快, 查找慢 由于链表实现, 增加时只要让前一个元素记住自 己就可以, 删除时让前一个元素记住后一个元 素, 后一个元素记住前一个元素. 这样的增删效 率较高但查询时需要一个一个的遍历, 所以效率 较低 ---|Vector: 和ArrayList原理相同, 但线程安全, 效率略低 和ArrayList实现方式相同, 但考虑了线程安全问 题, 所以效率略低 ---|Set: 无存储顺序, 不可重复 ---|HashSet ---|TreeSet ---|LinkedHashSet ---| Map: 键值对 ---|HashMap ---|TreeMap ---|HashTable ---|LinkedHashMap |
为什么出现这么多集合容器,因为每一个容器对数据的存储方式不同,这种存储方式称之为数据结构(data structure)
注意 集合和数组中存放的都是对象的引用。
1.1. 什么时候该使用什么样的集合
Collection | 我们需要保存若干个对象的时候使用集合。 |
List
| 如果我们需要保留存储顺序, 并且保留重复元素, 使用List. 如果查询较多, 那么使用ArrayList 如果存取较多, 那么使用LinkedList 如果需要线程安全, 那么使用Vector |
Set
| 如果我们不需要保留存储顺序, 并且需要去掉重复元素, 使用Set. 如果我们需要将元素排序, 那么使用TreeSet 如果我们不需要排序, 使用HashSet, HashSet比 TreeSet效率高. 如果我们需要保留存储顺序, 又要过滤重复元素, 那么使用LinkedHashSet |
2. 集合类(Collection)
Collection接口有两个子接口:
List(链表|线性表)
Set(集)
特点:
Collection中描述的是集合共有的功能(CRUD)
List可存放重复元素,元素存取是有序的
Set不可以存放重复元素,元素存取是无序的
java.util.Collection ---| Collection 描述所有接口的共性 ----| List接口 可以有重复元素的集合 ----| Set 接口 不可以有重复元素的集合
|
2:学习集合对象
学习Collection中的共性方法,多个容器在不断向上抽取就出现了该体系。发现Collection接口中具有所有容器都具备的共性方法。查阅API时,就可以直接看该接口中的方法。并创建其子类对象对集合进行基本应用。当要使用集合对象中特有的方法,在查看子类具体内容。
查看api 文档Collection在在java.util 中(注意是大写Collection)
注意在现阶段遇到的 E T 之类的类型,需要暂时理解为object 因为涉及到了泛型.
3:创建集合对象,使用Collection中的List的具体实现类ArrayList
1:Collection coll=new Arraylist();
2.1. Collection接口的共性方法
增加: 1:add() 将指定对象存储到容器中 add 方法的参数类型是Object 便于接收任意对象 2:addAll() 将指定集合中的元素添加到调用该方法和集合中 删除: 3:remove() 将指定的对象从集合中删除 4:removeAll() 将指定集合中的元素删除 修改 5:clear() 清空集合中的所有元素 判断 6:isEmpty() 判断集合是否为空 7:contains() 判断集合何中是否包含指定对象
8:containsAll() 判断集合中是否包含指定集合 使用equals()判断两个对象是否相等 获取: 9:int size() 返回集合容器的大小
转成数组10: toArray() 集合转换数组 |
2.1.1. 增加:
publicstaticvoid main(String[] args) { Collection list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); System.out.println(list); // [计算机网络, 现代操作系统, java编程思想]
// 增加2 将list容器元素添加到list2容器中 Collection list2 = new ArrayList(); list2.add("java核心技术"); list2.addAll(list); list2.add("java语言程序设计"); System.out.println(list2); // [java核心技术, 计算机网络, 现代操作系统, java编程思想, java语言程序设计] } |
2.1.2. 删除:
// 删除1 remove boolean remove = list2.remove("java核心技术"); System.out.println(remove); // true System.out.println(list2); // //删除2 removeAll() 将list中的元素删除 boolean removeAll = list2.removeAll(list); System.out.println(removeAll);//true System.out.println(list2);//[java语言程序设计] |
2.1.3. 修改:
publicstaticvoid main(String[] args) { Collection list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); list.add("java核心技术"); list.add("java语言程序设计"); System.out.println(list); // 修改 clear() 清空集合中的所有元素 list.clear(); System.out.println(list); //[] } |
2.1.4. 判断:
publicstaticvoid main(String[] args) { Collection list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); list.add("java核心技术"); list.add("java语言程序设计"); System.out.println(list);
boolean empty = list.isEmpty(); System.out.println(empty);// false boolean contains = list.contains("java编程思想"); System.out.println(contains);// true Collection list2 = new ArrayList(); list2.add("水许传"); boolean containsAll = list.containsAll(list2); System.out.println(containsAll);// false
} |
2.1.5. 获取:
publicstaticvoid main(String[] args) { Collection list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); list.add("java核心技术"); list.add("java语言程序设计"); System.out.println(list); // 获取 集合容器的大小 int size = list.size(); System.out.println(size); } |
2.2 List
---| Iterable 接口 Iterator iterator() ----| Collection 接口 ------| List 接口 元素可以重复,允许在指定位置插入元素,并通过索 引来访问元素 |
2.2.1. List集合特有方法
1:增加 void add(int index, E element) 指定位置添加元素 boolean addAll(int index, Collection c) 指定位置添加集合 2:删除 E remove(int index) 删除指定位置元素
3:修改 E set(int index, E element) 返回的是需要替换的集合中的元素 4:查找: E get(int index) 注意: IndexOutOfBoundsException int indexOf(Object o) // 找不到返回-1 lastIndexOf(Object o) 5:求子集合 List<E> subList(int fromIndex, int toIndex) // 不包含toIndex |
2.2.2. ArrayList
--| Iterable ----| Collection ------| List ---------| ArrayList 底层采用数组实现,默认10。每次增长 60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。 ---------| LinkedList |
ArrayList:实现原理:
数组实现, 查找快, 增删慢
数组为什么是查询快?因为数组的内存空间地址是连续的.
ArrayList底层维护了一个Object[] 用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。
当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。
由于ArrayList是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。数组是可以直接按索引查找, 所以查找时较快
可以考虑,假设向数组的0角标未知添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要要将老数组的内容拷贝到新数组中.所以数组的增删的效率是很低的.
练习:去除ArrayList集合中重复元素
1:存入字符串元素
2:存入自定义对象元素(如Perosn对象)
原理:
循环遍历该集合,每取出一个放置在新的集合中,放置之前先判断新的集合是否以包含了新的元素。
思路: 存入人的对象. 1先定义person 类 2将该类的实例存入集合 3 将对象元素进行操作. 注意:自定义对象要进行复写toString 和 equals 方法. 为什么? 因为object 是person 的父类,object 中的toString 返回的是哈希值,object 类中equals 方法比较的是对象的地址值. 思路 1存入字符串对象 2存入自定义对象如person 2创建容器,用于存储非重复元素 3对原容器进行遍历,在遍历过程中进行判断遍历到的元素是否在容器中存在.(contains) 4如果存在,就不存入,否则存入. 5 返回新容器 |
publicclass Demo6 { publicstaticvoid main(String[] args) { ArrayList arr = new ArrayList(); Person p1 = new Person("jack", 20); Person p2 = new Person("rose", 18); Person p3 = new Person("rose", 18); arr.add(p1); arr.add(p2); arr.add(p3); System.out.println(arr); ArrayList arr2 = new ArrayList(); for (int i = 0; i < arr.size(); i++) { Object obj = arr.get(i); Person p = (Person) obj; if (!(arr2.contains(p))) { arr2.add(p); } } System.out.println(arr2); } }
class Person { private String name; privateintage;
public Person() {
}
public Person(String name, int age) {
this.name = name; this.age = age; }
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
publicint getAge() { returnage; }
publicvoid setAge(int age) { this.age = age; }
@Override publicint hashCode() { returnthis.name.hashCode() + age * 37; }
@Override publicboolean equals(Object obj) { if (!(obj instanceof Person)) { returnfalse; } Person p = (Person) obj;
returnthis.name.equals(p.name) && this.age == p.age; }
@Override public String toString() { return"Person@name:" + this.name + " age:" + this.age; }
} |
在实际的开发中ArrayList是使用频率最高的一个集合。
2.2.3. LinkedList
--| Iterable ----| Collection ------| List ---------| ArrayList 底层采用数组实现,默认10。每次增长 60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。 ---------| LinkedList 底层采用链表实现,增删快,查询慢。 |
LinkedList:链表实现, 增删快, 查找慢
由于LinkedList:在内存中的地址不连续,需要让上一个元素记住下一个元素.所以每个元素中保存的有下一个元素的位置.虽然也有角标,但是查找的时候,需要从头往下找,显然是没有数组查找快的.但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了.所以插入很快.
由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高。
但查询时需要一个一个的遍历, 所以效率较低。
特有方法
1:方法介绍 addFirst(E e) addLast(E e) getFirst() getLast() removeFirst() removeLast() 如果集合中没有元素,获取或者删除元 素抛:NoSuchElementException 2:数据结构 1:栈 (1.6) 先进后出 push() pop() 2:队列(双端队列1.5) 先进先出 offer() poll() 3:返回逆序的迭代器对象 descendingIterator() 返回逆序的迭代器对象
|
基本方法
import java.util.Iterator; import java.util.LinkedList;
publicclass Demo3 { publicstaticvoid main(String[] args) { LinkedList list = new LinkedList(); list.add("西游记"); list.add("三国演义"); list.add("石头记"); list.add("水浒传"); list.add("全球通史"); list.addFirst("史记"); list.addLast("呐喊"); // list.addFirst(null); // list.addLast(null); System.out.println(list); // 获取指定位置处的元素。 String str = (String) list.get(0); // 返回此列表的第一个元素。 String str2 = (String) list.getFirst(); System.out.println(str.equals(str2));
// 获取指定位置处的元素。 String str3 = (String) list.get(list.size() - 1); // 返回此列表的最后一个元素。 String str4 = (String) list.getLast(); System.out.println(str3.equals(str4));
// 获取但不移除此列表的头(第一个元素)。 Object element = list.element(); System.out.println(element);
int size = list.size(); System.out.println(size); }
|
迭代
mport java.util.Iterator; import java.util.LinkedList;
publicclass Demo3 { publicstaticvoid main(String[] args) { LinkedList list = new LinkedList(); list.add("西游记"); list.add("三国演义"); list.add("石头记"); list.add("水浒传"); list.add("全球通史"); Iterator it = list.iterator(); while (it.hasNext()) { String next = (String) it.next(); System.out.println(next); } } } |
逆序迭代
import java.util.Iterator; import java.util.LinkedList;
publicclass Demo6 { publicstaticvoid main(String[] args) { LinkedList list = new LinkedList(); list.add("aa"); list.add("bb"); list.add("cc"); Iterator dit = list.descendingIterator(); while (dit.hasNext()) { System.out.println(dit.next()); } } }
|
注意:可以使用该集合去模拟出队列(先进先出) 或者堆栈(后进先出) 数据结构。
堆栈(后进先出)
//堆栈(后进先出) 数据结构 publicclass Demo3 { publicstaticvoid main(String[] args) { LinkedList list = new LinkedList(); // 压栈,先进后出 list.push("西游记"); list.push("三国演义"); list.push("石头记"); list.push("水浒传"); System.out.println(list); // 弹栈 String str1 = (String) list.pop(); System.out.println(str1); String str2 = (String) list.pop(); System.out.println(str2); String str3 = (String) list.pop(); System.out.println(str3); String str4 = (String) list.pop(); System.out.println(str4); System.out.println(list.size());// 0 System.out.println(list); //[] } }
|
队列,先进先出
import java.util.LinkedList;
publicclass Demo3 { publicstaticvoid main(String[] args) { LinkedList list = new LinkedList(); // 队列,先进先出 list.offer("西游记"); list.offer("三国演义"); list.offer("石头记"); list.offer("水浒传"); System.out.println(list); // 出队列 System.out.println(list.poll()); System.out.println(list.poll()); System.out.println(list.poll()); System.out.println(list.poll());
System.out.println(list.size());
System.out.println(list.peek()); // 获取队列的头元素,但是不删除 System.out.println(list.peekFirst()); // 获取队列的头元素,但是不删除 System.out.println(list.peekLast()); // 获取队列的最后一个元素但是不删除
} }
|
ArrayList 和 LinkedList的存储查找的优缺点:
1、ArrayList 是采用动态数组来存储元素的,它允许直接用下标号来直接查找对应的元素。但是,但是插入元素要涉及数组元素移动及内存的操作。总结:查找速度快,插入操作慢。
2、LinkedList 是采用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快
问题:有一批数据要存储,要求存储这批数据不能出现重复数据,ArrayList、LinkedList都没法满足需求。解决办法:使用 set集合。
2.2.4. Vector
Vector: 描述的是一个线程安全的ArrayList。
ArrayList:单线程效率高
Vector :多线程安全的,所以效率低
特有的方法:
void addElement(E obj) 在集合末尾添加元素 E elementAt( int index) 返回指定角标的元素 Enumeration elements() 返回集合中的所有元素,封装到Enumeration对象中
Enumeration 接口:
boolean hasMoreElements() 测试此枚举是否包含更多的元素。 E nextElement() 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。 |
publicstaticvoid main(String[] args) { Vector v = new Vector(); v.addElement("aaa"); v.addElement("bbb"); v.addElement("ccc"); System.out.println( v ); System.out.println( v.elementAt(2) ); // ccc // 遍历Vector遍历 Enumeration ens = v.elements(); while ( ens.hasMoreElements() ) { System.out.println( ens.nextElement() ); } } |
2.3. 迭代器
2.3.1. Iterator
Iterator iterator() 返回该集合的迭代器对象
该类主要用于遍历集合对象,该类描述了遍历集合的常见方法 1:java.lang.Itreable ---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 可以有重复元素的集合 ---| Set接口 不可以有重复元素的集合 |
public interface Iterable<T>
Itreable 该接口仅有一个方法,用于返回集合迭代器对象。
1: Iterator<T> iterator() 返回集合的迭代器对象
Iterator接口定义的方法
Itreator 该接口是集合的迭代器接口类,定义了常见的迭代方法 1:boolean hasNext() 判断集合中是否有元素,如果有元素可以迭代,就返回true。 2: E next() 返回迭代的下一个元素,注意: 如果没有下一个元素时,调用 next元素会抛出NoSuchElementException
3: void remove() 从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操 作)。 |
思考:为什么next方法的返回类型是Object的呢? 为了可以接收任意类型的对象,那么返回的时候,不知道是什么类型的就定义为object
2.3.2. 迭代器遍历
1:while循环
publicstaticvoid main(String[] args) { ArrayList list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); list.add("java核心技术"); list.add("java语言程序设计"); System.out.println(list); Iterator it = list.iterator(); while (it.hasNext()) { String next = (String) it.next(); System.out.println(next); } } |
2:for循环
import java.util.ArrayList; import java.util.Iterator;
publicclass Demo2 { publicstaticvoid main(String[] args) { ArrayList list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); list.add("java核心技术"); list.add("java语言程序设计"); System.out.println(list);
for (Iterator it = list.iterator(); it.hasNext();) { //迭代器的next方法返回值类型是Object,所以要记得类型转换。 String next = (String) it.next(); System.out.println(next); } } }
|
需要取出所有元素时,可以通过循环,java 建议使用for 循环。因为可以对内存进行一下优化。
3:使用迭代器清空集合
publicclass Demo1 { publicstaticvoid main(String[] args) { Collection coll = new ArrayList(); coll.add("aaa"); coll.add("bbb"); coll.add("ccc"); coll.add("ddd"); System.out.println(coll); Iterator it = coll.iterator(); while (it.hasNext()) { it.next(); it.remove(); } System.out.println(coll); } } |
2.3.3. List特有的迭代器ListIterator
public interface ListIterator extends Iterator
ListIterator<E> listIterator()
---| Iterator hasNext() next() remove() ------| ListIterator Iterator子接口 List专属的迭代器 add(E e) 将指定的元素插入列表(可选操作)。该元素直接插入到next返回的下一个元素的前面(如果有) void set(E o) 用指定元素替换next或previous返回的最后一个元素 hasPrevious() 逆向遍历列表,列表迭代器有多个元素,则返回true。 previous() 返回列表中的前一个元素。 |
Iterator在迭代时,只能对元素进行获取(next())和删除(remove())的操作。
对于 Iterator 的子接口ListIterator 在迭代list 集合时,还可以对元素进行添加
(add(obj)),修改set(obj)的操作。
2.4. Set
Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素
用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。
对象的相等性
引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。
如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true
该集合中没有特有的方法,直接继承自Collection。
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 可以有重复元素的集合 ---| ArrayList ---| LinkedList ---| Set接口 不可以有重复元素的集合 |
案例:set集合添加元素并使用迭代器迭代元素。
import java.util.HashSet; import java.util.Iterator; import java.util.Set;
publicclass Demo4 { publicstaticvoid main(String[] args) { //Set 集合存和取的顺序不一致。 Set hs = new HashSet(); hs.add("世界军事"); hs.add("兵器知识"); hs.add("舰船知识"); hs.add("汉和防务"); System.out.println(hs); // [舰船知识, 世界军事, 兵器知识, 汉和防务] Iterator it = hs.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } |
2.4.1. HashSet
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 可以有重复元素的集合 ---| ArrayList ---| LinkedList ---| Set接口 不可以有重复元素的集合 ---| HashSet 线程不安全,存取速度快。底层是以哈希表实现的。 |
HashSet
哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。
HashSet不存入重复元素的规则.使用hashcode和equals
由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。
练习:使用HashSet存储字符串,并尝试添加重复字符串
回顾String类的equals()、hashCode()两个方法。
import java.util.HashSet; import java.util.Iterator; import java.util.Set;
publicclass Demo4 { publicstaticvoid main(String[] args) { // Set 集合存和取的顺序不一致。 Set hs = new HashSet(); hs.add("世界军事"); hs.add("兵器知识"); hs.add("舰船知识"); hs.add("汉和防务");
// 返回此 set 中的元素的数量 System.out.println(hs.size()); // 4
// 如果此 set 尚未包含指定元素,则返回 true boolean add = hs.add("世界军事"); // false System.out.println(add);
// 返回此 set 中的元素的数量 System.out.println(hs.size());// 4 Iterator it = hs.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } }
|
使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定)
package cn.itcast.gz.map;
import java.util.HashSet; import java.util.Iterator;
publicclass Demo4 { publicstaticvoid main(String[] args) { HashSet hs = new HashSet(); hs.add(new Person("jack", 20)); hs.add(new Person("rose", 20)); hs.add(new Person("hmm", 20)); hs.add(new Person("lilei", 20)); hs.add(new Person("jack", 20));
Iterator it = hs.iterator(); while (it.hasNext()) { Object next = it.next(); System.out.println(next); } } }
class Person { private String name; privateintage;
Person() {
}
public Person(String name, int age) {
this.name = name; this.age = age; }
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
publicint getAge() { returnage; }
publicvoid setAge(int age) { this.age = age; }
@Override publicint hashCode() { System.out.println("hashCode:" + this.name); returnthis.name.hashCode() + age * 37; }
@Override publicboolean equals(Object obj) { System.out.println(this + "---equals---" + obj); if (obj instanceof Person) { Person p = (Person) obj; returnthis.name.equals(p.name) && this.age == p.age; } else { returnfalse; } }
@Override public String toString() {
return"Person@name:" + this.name + " age:" + this.age; }
}
|
问题:现在有一批数据,要求不能重复存储元素,而且要排序。ArrayList 、 LinkedList不能去除重复数据。HashSet可以去除重复,但是是无序。
2.4.2. TreeSet
案例:使用TreeSet集合存储字符串元素,并遍历
import java.util.TreeSet;
publicclass Demo5 { publicstaticvoid main(String[] args) { TreeSet ts = new TreeSet(); ts.add("ccc"); ts.add("aaa"); ts.add("ddd"); ts.add("bbb");
System.out.println(ts); // [aaa, bbb, ccc, ddd]
} } |
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 有序,可以重复,有角标的集合 ---| ArrayList ---| LinkedList ---| Set接口 无序,不可以重复的集合 ---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。 ---| TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。 |
比较器接口
----| Comparable compareTo(Object o) 元素自身具备比较性 ----| Comparator compare( Object o1, Object o2 ) 给容器传入比较器 |
TreeSet集合排序的两种方式:
一,让元素自身具备比较性。
也就是元素需要实现Comparable接口,覆盖compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。
年龄按照搜要条件,年龄相同再比姓名。
import java.util.TreeSet;
publicclass Demo4 { publicstaticvoid main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Person("aa", 20, "男")); ts.add(new Person("bb", 18, "女")); ts.add(new Person("cc", 17, "男")); ts.add(new Person("dd", 17, "女")); ts.add(new Person("dd", 15, "女")); ts.add(new Person("dd", 15, "女"));
System.out.println(ts); System.out.println(ts.size()); // 5
} }
class Person implements Comparable { private String name; privateintage; private String gender;
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name; this.age = age; this.gender = gender; }
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
publicint getAge() { returnage; }
publicvoid setAge(int age) { this.age = age; }
public String getGender() { returngender; }
publicvoid setGender(String gender) { this.gender = gender; }
@Override publicint hashCode() { returnname.hashCode() + age * 37; }
publicboolean equals(Object obj) { System.err.println(this + "equals :" + obj); if (!(obj instanceof Person)) { returnfalse; } Person p = (Person) obj; returnthis.name.equals(p.name) && this.age == p.age;
}
public String toString() { return"Person [name=" + name + ", age=" + age + ", gender=" + gender + "]"; }
@Override publicint compareTo(Object obj) {
Person p = (Person) obj; System.out.println(this+" compareTo:"+p); if (this.age > p.age) { return 1; } if (this.age < p.age) { return -1; } returnthis.name.compareTo(p.name); }
}
|
二,让容器自身具备比较性,自定义比较器。
需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。
那么这时只能让容器自身具备。
定义一个类实现Comparator 接口,覆盖compare方法。
并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。
当Comparable比较方式,及Comparator比较方式同时存在,以Comparator
比较方式为主。
import java.util.Comparator; import java.util.TreeSet;
publicclass Demo5 { publicstaticvoid main(String[] args) { TreeSet ts = new TreeSet(new MyComparator()); ts.add(new Book("think in java", 100)); ts.add(new Book("java 核心技术", 75)); ts.add(new Book("现代操作系统", 50)); ts.add(new Book("java就业教程", 35)); ts.add(new Book("think in java", 100)); ts.add(new Book("ccc in java", 100));
System.out.println(ts); } }
class MyComparator implements Comparator {
publicint compare(Object o1, Object o2) { Book b1 = (Book) o1; Book b2 = (Book) o2; System.out.println(b1+" comparator "+b2); if (b1.getPrice() > b2.getPrice()) { return 1; } if (b1.getPrice() < b2.getPrice()) { return -1; } return b1.getName().compareTo(b2.getName()); }
}
class Book { private String name; privatedoubleprice;
public Book() {
}
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
publicdouble getPrice() { returnprice; }
publicvoid setPrice(double price) { this.price = price; }
public Book(String name, double price) {
this.name = name; this.price = price; }
@Override public String toString() { return"Book [name=" + name + ", price=" + price + "]"; }
} |
3. Map
Map学习体系: ---| Map 接口 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。 ---| HashMap 采用哈希表实现,所以无序 ---| TreeMap 可以对健进行排序 |
---|Hashtable: 底层是哈希表数据结构,线程是同步的,不可以存入null键,null值。 效率较低,被HashMap 替代。 ---|HashMap: 底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。 要保证键的唯一性,需要覆盖hashCode方法,和equals方法。 ---|LinkedHashMap: 该子类基于哈希表又融入了链表。可以Map集合进行增删提高效率。 ---|TreeMap: 底层是二叉树数据结构。可以对map集合中的键进行排序。需要使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性。 |
常见方法
1、添加: 1、V put(K key, V value) (可以相同的key值,但是添加的value值会覆 盖前面的,返回值是前一个,如果没有就返回null) 2、putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关 系复制到此映射中(可选操作)。 2、删除 1、remove() 删除关联对象,指定key对象 2、clear() 清空集合对象 3、获取 1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返 回的是null。
3、判断: 1、boolean isEmpty() 长度为0返回true否则false 2、boolean containsKey(Object key) 判断集合中是否包含指定的key 3、boolean containsValue(Object value) 判断集合中是否包含指定的value 4、长度: Int size()
|
遍历Map的方式:
1、将map 集合中所有的键取出存入set集合。 Set<K> keySet() 返回所有的key对象的Set集合 再通过get方法获取键对应的值。 2、 values() ,获取所有的值. Collection<V> values()不能获取到key对象 3、 Map.Entry对象 推荐使用 重点 Set<Map.Entry<k,v>> entrySet() 将map 集合中的键值映射关系打包成一个对象 Map.Entry对象通过Map.Entry 对象的getKey, getValue获取其键和值。 |
|
第一种方式:使用keySet
将Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set;
publicclass Demo2 { publicstaticvoid main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "aaaa"); map.put(2, "bbbb"); map.put(3, "cccc"); System.out.println(map);
// // 获取方法: // 第一种方式: 使用keySet // 需要分别获取key和value,没有面向对象的思想 // Set<K> keySet() 返回所有的key对象的Set集合
Set<Integer> ks = map.keySet(); Iterator<Integer> it = ks.iterator(); while (it.hasNext()) { Integer key = it.next(); String value = map.get(key); System.out.println("key=" + key + " value=" + value); } } }
|
第二种方式:通过values 获取所有值,不能获取到key对象
publicstaticvoid main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "aaaa"); map.put(2, "bbbb"); map.put(3, "cccc"); System.out.println(map); // 第二种方式: // 通过values 获取所有值,不能获取到key对象 // Collection<V> values()
Collection<String> vs = map.values(); Iterator<String> it = vs.iterator(); while (it.hasNext()) { String value = it.next(); System.out.println(" value=" + value); } } |
第三种方式: Map.Entry
public static interface Map.Entry<K,V>
通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。
Set<Map.Entry<K,V>> entrySet()
面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry
,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。
publicstaticvoid main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "aaaa"); map.put(2, "bbbb"); map.put(3, "cccc"); System.out.println(map); // 第三种方式: Map.Entry对象推荐使用重点 // Set<Map.Entry<K,V>> entrySet()
// 返回的Map.Entry对象的Set集合 Map.Entry包含了key和value对象 Set<Map.Entry<Integer, String>> es = map.entrySet();
Iterator<Map.Entry<Integer, String>> it = es.iterator();
while (it.hasNext()) {
// 返回的是封装了key和value对象的Map.Entry对象 Map.Entry<Integer, String> en = it.next();
// 获取Map.Entry对象中封装的key和value对象 Integer key = en.getKey(); String value = en.getValue();
System.out.println("key=" + key + " value=" + value); } } |
3.1. HashMap
底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
案例:自定义对象作为Map的键。
package cn.itcast.gz.map;
import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set;
publicclass Demo3 { publicstaticvoid main(String[] args) { HashMap<Person, String> hm = new HashMap<Person, String>(); hm.put(new Person("jack", 20), "1001"); hm.put(new Person("rose", 18), "1002"); hm.put(new Person("lucy", 19), "1003"); hm.put(new Person("hmm", 17), "1004"); hm.put(new Person("ll", 25), "1005"); System.out.println(hm); System.out.println(hm.put(new Person("rose", 18), "1006"));
Set<Entry<Person, String>> entrySet = hm.entrySet(); Iterator<Entry<Person, String>> it = entrySet.iterator(); while (it.hasNext()) { Entry<Person, String> next = it.next(); Person key = next.getKey(); String value = next.getValue(); System.out.println(key + " = " + value); } } }
class Person { private String name; privateintage;
Person() {
}
public Person(String name, int age) {
this.name = name; this.age = age; }
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
publicint getAge() { returnage; }
publicvoid setAge(int age) { this.age = age; }
@Override publicint hashCode() {
returnthis.name.hashCode() + age * 37; }
@Override publicboolean equals(Object obj) { if (obj instanceof Person) { Person p = (Person) obj; returnthis.name.equals(p.name) && this.age == p.age; } else { returnfalse; } }
@Override public String toString() {
return"Person@name:" + this.name + " age:" + this.age; }
} }
|
3.2. TreeMap
TreeMap的排序,TreeMap可以对集合中的键进行排序。如何实现键的排序?
方式一:元素自身具备比较性
和TreeSet一样原理,需要让存储在键位置的对象实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,以为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
通过return 0来判断唯一性。
import java.util.TreeMap;
publicclass Demo4 { publicstaticvoid main(String[] args) { TreeMap<String, Integer> tree = new TreeMap<String, Integer>(); tree.put("张三", 19); tree.put("李四", 20); tree.put("王五", 21); tree.put("赵六", 22); tree.put("周七", 23); tree.put("张三", 24); System.out.println(tree); System.out.println("张三".compareTo("李四"));//-2094 } } |
自定义元素排序
package cn.itcast.gz.map;
import java.util.Comparator; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap;
publicclass Demo3 { publicstaticvoid main(String[] args) { TreeMap<Person, String> hm = new TreeMap<Person, String>( new MyComparator()); hm.put(new Person("jack", 20), "1001"); hm.put(new Person("rose", 18), "1002"); hm.put(new Person("lucy", 19), "1003"); hm.put(new Person("hmm", 17), "1004"); hm.put(new Person("ll", 25), "1005"); System.out.println(hm); System.out.println(hm.put(new Person("rose", 18), "1006"));
Set<Entry<Person, String>> entrySet = hm.entrySet(); Iterator<Entry<Person, String>> it = entrySet.iterator(); while (it.hasNext()) { Entry<Person, String> next = it.next(); Person key = next.getKey(); String value = next.getValue(); System.out.println(key + " = " + value); } } }
class MyComparator implements Comparator<Person> {
@Override publicint compare(Person p1, Person p2) { if (p1.getAge() > p2.getAge()) { return -1; } elseif (p1.getAge() < p2.getAge()) { return 1; } return p1.getName().compareTo(p2.getName()); }
}
class Person implements Comparable<Person> { private String name; privateintage;
Person() {
}
public Person(String name, int age) {
this.name = name; this.age = age; }
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
publicint getAge() { returnage; }
publicvoid setAge(int age) { this.age = age; }
@Override publicint hashCode() {
returnthis.name.hashCode() + age * 37; }
@Override publicboolean equals(Object obj) { if (obj instanceof Person) { Person p = (Person) obj; returnthis.name.equals(p.name) && this.age == p.age; } else { returnfalse; } }
@Override public String toString() {
return"Person@name:" + this.name + " age:" + this.age; }
@Override publicint compareTo(Person p) {
if (this.age > p.age) { return 1; } elseif (this.age < p.age) { return -1; } returnthis.name.compareTo(p.name); }
} |
注意:Set的元素不可重复,Map的键不可重复,如果存入重复元素如何处理
Set元素重复元素不能存入add方法返回false
Map的重复健将覆盖旧键,将旧值返回。
4. Collections与Arrays
集合框架中的工具类:特点:该工具类中的方法都是静态的。
Collections:常见方法: 1, 对list进行二分查找: 前提该集合一定要有序。 int binarySearch(list,key); //必须根据元素自然顺序对列表进行升级排序 //要求list 集合中的元素都是Comparable 的子类。 int binarySearch(list,key,Comparator); 2,对list集合进行排序。 sort(list); //对list进行排序,其实使用的事list容器中的对象的compareTo方法 sort(list,comaprator); //按照指定比较器进行排序 3,对集合取最大值或者最小值。 max(Collection) max(Collection,comparator) min(Collection) min(Collection,comparator) reverse(list); 5,对比较方式进行强行逆转。 Comparator reverseOrder(); Comparator reverseOrder(Comparator); 6,对list集合中的元素进行位置的置换。 swap(list,x,y); 7,对list集合进行元素的替换。如果被替换的元素不存在,那么原集合不变。 replaceAll(list,old,new); 8,可以将不同步的集合变成同步的集合。 Set synchronizedSet(Set<T> s) Map synchronizedMap(Map<K,V> m) List synchronizedList(List<T> list) 9. 如果想要将集合变数组: 可以使用Collection 中的toArray 方法。注意:是Collection不是Collections工具类 传入指定的类型数组即可,该数组的长度最好为集合的size。 |
Arrays:用于对数组操作的工具类
1,二分查找,数组需要有序 binarySearch(int[]) binarySearch(double[])
2,数组排序 sort(int[]) sort(char[])…… 2, 将数组变成字符串。 toString(int[]) 3, 复制数组。 4, 复制部分数组。 copyOfRange(): 5, 比较两个数组是否相同。 equals(int[],int[]); 6, 将数组变成集合。 List asList(T[]); 这样可以通过集合的操作来操作数组中元素, 但是不可以使用增删方法,add,remove。因为数组长度是固定的,会出现 UnsupportOperationExcetion。 可以使用的方法:contains,indexOf。。。 如果数组中存入的基本数据类型,那么asList会将数组实体作为集合中的元素。 如果数组中的存入的引用数据类型,那么asList会将数组中的元素作为集合中 的元素。 |
import java.util.ArrayList; import java.util.Collections; import java.util.Arrays; import java.util.List; class Demo1 { publicstaticvoid main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(4); list.add(3); list.add(1); list.add(2); list.add(3); // 排序 Collections.sort(list); // 折半查找的前提是排序好的元素 System.out.println( Collections.binarySearch( list , 8 ) ); // 找不到返回-插入点-1 // 反序集合输出 Collections.reverse( list ); System.out.println( list ); // 求最值 System.out.println( Collections.max( list ) ); // 4 // fill() 使用指定的元素替换指定集合中的所有元素 // Collections.fill( list, 5 ); System.out.println( list );
// 将数组转换为集合 Integer is[] = new Integer[]{6,7,8}; List<Integer> list2 = Arrays.asList(is); list.addAll( list2 ); System.out.println( list );
// 将List转换为数组 Object [] ins = list.toArray(); System.out.println( Arrays.toString( ins ) );
} } |