Collection
数组:
缺点:(1)长度固定,如果要扩容等需要程序自己维护,如果要删除和插入,程序员要移动元素等
(2)数组只支持“可重复,顺序存储”特点,比较单一
集合:很多种容器
实际开发中,数据的存储特点:(1)有序的(2)无序的(3)可以重复的(4)不能重复的(5)一对一的(6)一对多…
JDK在(1)数组(2)链式结构基础上,重新设计出了很多的容器类型。
*
主要是两大类:
1、Collection:一组对象,比喻"单身party"
2、Map:键值对,(key,value),比喻“情侣party”,“家庭party"
容器有共同的行为特征,操作方式:
增、删、改、查…
把对容器的操作的行为标准化,用接口来声明。
一、java.util.Collection
(一)Collection概述
Collection 层次结构 中的根接口。Collection 表示一组对象。
一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。
1、List
列表:可重复的,有序的(按顺序存储)
实现类:例如ArrayList(动态数组)
2、Set
集:不可重复的,无序的(和添加顺序无关)
(二)Collection的常用方法
1、添加
(1)add(Object obj):一次添加一个
(2)addAll(Collection other):一次添加多个,把other中的元素都添加到当前集合中
this = this ∪(并) other
2、删除
(1)remove(Object o) :一次删除一个
(2)removeAll(Collection other):一次删除多个
this = this - this ∩(交) other
(3)clear()
3、修改:Collection根接口中没有提供修改的方法
4、查询
(1)boolean contains(Object o) :判断o是否在当前集合中
(2)boolean containsAll(Collection<?> c):判断c中的元素都在当前集合中
即判断c是否是this的子集
(3)boolean isEmpty()
Collection根接口中没有提供获取一个元素的方法。
5、获取有效元素的个数
int size()
6、遍历
(1)老方法
Object[] toArray():如果该集合的底层实现就是数组,那么比较简单,但是如果该集合的底层不是数组,那么就比较麻烦。
无论底层怎么样,都会返回一个size长度的数组,所以比较浪费空间。
(2)foreach
(2)Iterator迭代器遍历
7、其他
retainAll(Collection<?> c) :保留当前集合和c集合的交集
this = this ∩ c
public class TestCollection {
@SuppressWarnings("all")
@Test
public void test3(){
Collection c = new ArrayList();
c.add("张三");
c.add("李四");
c.add("王五");
c.add("钱七");
Collection other = new ArrayList();
other.add("王五");
other.add("赵六");
c.retainAll(other);
Object[] array = c.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
@SuppressWarnings("all")
@Test
public void test2(){
Collection c = new ArrayList();
c.add("张三");
c.add("李四");
c.add("王五");
c.add("赵六");
c.add("钱七");
Collection other = new ArrayList();
other.add("王五");
other.add("赵六");
// c.remove("张三");
c.removeAll(other);
Object[] array = c.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
@SuppressWarnings("all")
@Test
public void test1(){
//多态引用,关注Collection的方法,ArrayList是Collection子接口List的实现类
Collection c = new ArrayList();
c.add("张三");
c.add("李四");
Collection other = new ArrayList();
other.add("王五");
other.add("赵六");
c.addAll(other);
// c.add(other);
System.out.println(c.size());
Object[] array = c.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
List
/*
- java.util.List:接口
- (1)有序:可以对元素的索引index,进行控制。
- (2)可重复。
- 常用方法:
- 继承了Collection,因此,Collection的所有的方法和操作它都有。
- List还增加了很多方法,这些方法都和index相关。
- 1、添加
- add(int index, E element) :在index位置插入一个元素
- addAll(int index, Collection<? extends E> c):在index位置插入多个元素
- 2、删除
- remove(int index)
- 3、改
- 刚才Collection根接口没有提供修改的方法
- set(int index, E element)
- 4、查
- int indexOf(Object o) :从前往后
- int lastIndexOf(Object o ):从后往前
- get(int index) :返回index位置的元素
- subList(int fromIndex, int toIndex) :截取[fromIndex,toIndex)
- 5、遍历
- (1)toArray
- (2)foreach
- (3)Iterator
- (4)ListIterator
-
ListIterator是Iterator的子接口,Iterator有的,ListIterator也有,还增加了:
- A:Iterator只能从前往后遍历
- ListIterator可以从任意位置开始,从前往后,或从后往前遍历
- ListIterator的使用步骤:
- 第一步:先获取ListIterator的对象
-
集合对象.listIterator()
- 第二步:通过遍历方法
-
hasNext()+next()
-
hasPrevious() + previous()
- B:不仅可以在遍历是删除了,还增加了set和add方法。
*/
public class TestList {
@SuppressWarnings("all")
@Test
public void test5(){
List list = new ArrayList();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("前提");
list.add("王八");
//从前往后
ListIterator listIterator = list.listIterator();//默认迭代器指向最前面
while(listIterator.hasNext()){
Object next = listIterator.next();
System.out.println(next);
}
System.out.println();
//从最后往前
listIterator = list.listIterator(list.size());//要让迭代器先指到最后
while(listIterator.hasPrevious()){
Object previous = listIterator.previous();
System.out.println(previous);
}
System.out.println();
//从任意位置开始遍历
listIterator = list.listIterator(3);//要让迭代器先指到某个位置
while(listIterator.hasPrevious()){
Object previous = listIterator.previous();
System.out.println(previous);
}
}
@SuppressWarnings("all")
@Test
public void test4(){
List list = new ArrayList();
list.add("张三");
list.add("李四");
list.add("王五");
int index = list.indexOf("张三");
System.out.println(index);
Object object = list.get(2);
System.out.println(object);
}
@SuppressWarnings("all")
@Test
public void test3(){
List list = new ArrayList();
list.add("张三");
list.add("李四");
list.add("王五");
list.set(0, "曹阳");
for (Object object : list) {
System.out.println(object);
}
}
@SuppressWarnings("all")
@Test
public void test2(){
List list = new ArrayList();
list.add("张三");
list.add("李四");
list.add("王五");
list.remove(0);
for (Object object : list) {
System.out.println(object);
}
}
@SuppressWarnings("all")
@Test
public void test1(){
List list = new ArrayList();
list.add("张三");
list.add(0, "李四");
for (Object object : list) {
System.out.println(object);
}
}
}
/*
- List的常见的实现类:
- 1、Vector:动态数组
-
内部实现:数组,初始化大小为10
- 2、ArrayList:动态数组
-
内部实现:数组,初始化大小为10
- 3、LinkedList:双向链表、双端队列
-
LinkedList实现了List、Queue、Deque接口
-
内部实现:链表
- 4、Stack:栈,又是Vector的子类
-
内部实现:数组
- Stack:后进先出(LIFO)(Last in First out)、先进后出(FILO)(First in Last out)
-
压栈:push,弹栈:pop(移除栈顶元素),peek(返回栈顶元素,但不移除)
- 队列(Queue):先进先出(FIFO)
-
添加到队列offer(e),移出队列,poll(),返回队头不移除peek()
- 双端队列(Deque)(Double ended queue):队头和队尾都可以添加元素和移除元素
-
offerFirst(e)、offerLast(e)
-
pollFirst()、pollLast()
-
peekFirst()、peekLast()
- 面试题:Vector与ArrayList有什么区别?
- Vector:旧版,线程安全的,扩容为原来的2倍,支持迭代的方式更多,支持旧版Enumeration迭代器
- ArrayList:新版,线程不安全,扩容为原来的1.5倍,不支持老版的Enumeration迭代器
- 面试题:动态数组和LinkedList有什么区别?
- (1)内部实现不同:
- 动态数组底层数组
- LinkedList是链表,元素的类型是节点类型,Node(prev,data,next)
- (2)动态数组:对索引的相关操作,效率很高
-
链表:对索引的相关操作,效率比较低
- (3)动态数组:插入、删除,涉及到移动元素
- 链表 :插入,删除,只涉及到前后的元素的关系
- 结论:如果是后面的操作针对索引更多,那么选择动态数组,如果是添加和删除,插入等操作更多,选择链表
*/
map
-
java.util.Map:接口
-
和Collection最大的不同,就是它存储“键值对,映射关系”
-
常用方法:
-
1、添加
-
put(key,value):一次添加一对映射关系
-
putAll(Map map):一次添加多对映射关系
-
2、删除
-
remove(Object key);根据key删除一对
-
clear():清空
-
3、修改
-
通过put可以替换value,只要key相同,就会替换
-
4、查询
-
(1)containsKey(Object key):判断某个key是否存在
-
(2)containsValue(Object value):判断某个value是否存在
-
(3)V get(Object key):根据key获取value
-
(4)boolean isEmpty() :是否为空
-
5、获取映射关系,键值对数:int size()
-
6、遍历
-
(1)Set keySet()
-
(2)Collection values()
-
(3)Set entrySet():由entry对象构成的set,因为key不重复,那么entry对象也不会重复
-
Map的实现类们:
-
1、HashMap:哈希表
-
2、Hashtable:哈希表
-
3、LinkedHashMap:
-
它是HashMap的子类,比HashMap多维护了添加的顺序。
-
4、TreeMap:映射关系的顺序会按照key的“大小”顺序排列
-
要求:映射关系的key,必须支持排序,即实现java.lang.Comparable接口,或者单独为TreeMap指定定制比较器对象。
-
5、Properties:
-
(1)Properties是Hashtable的子类
-
(2)Properties的key和value的类型是String
-
面试题:Hashtable与HashMap的区别
-
Hashtable:最古老,线程安全的,它的key和value不允许为null
-
HashMap:相对新,线程不安全,它的key和value都允许为null
-
类同:StringBuffer与StringBuilder、Vector与ArrayList
set
- java.util.Set:接口,是Collection的子接口。
- (1)不支持重复
- (2)无序的(和添加顺序无关)
- Set没有增加方法,都是Collection接口的方法。
- Set:
- (1)HashSet:完全无序
-
如何保证两个元素不重复?依据元素的equals方法
- (2)TreeSet:大小顺序,和添加顺序无关
-
如何保证两个元素不重复?依据元素的“大小”顺序
- (3)LinkedHashSet:遍历时可以保证添加顺序,存储和添加顺序无关
-
LinkedHashSet是HashSet的子类,但是它的元素比HashSet的元素要多维护一个添加的顺序。
-
LinkedHashSet的效率就比HashSet低,每次添加,删除,要同时考虑顺序。
-
LinkedHashSet和HashSet一样依据equals,决定是否重复。
- 结论:如果既要元素不重复,又要按大小,选TreeSet
-
如果既要元素不重复,又要保证添加顺序,选LinkedHashSet
-
如果只是要元素不重复,选择HashSet
下面是一个例子
题目
1、声明一个Book类型,有编号、书名、作者、价格,销量
2、添加到一个集合中,要求不可重复,规定编号相同就认为是一本书
提示:HashSet
3、添加到一个集合中,要求不可重复,但是要求按照销量从高到低排序
提示:TreeSet
4、添加到一个集合中,要求不可重复,但是要求这次按照价格从低到高排序
提示:TreeSet
5、添加到一个集合中,要求不可重复,但是要求按照添加顺序显示
提示:LinkedHashSet
book类
package day21.homework;
import java.util.Comparator;
import java.util.Objects;
public class Book implements Comparable<Book> {
/**
* 1、声明一个Book类型,有编号、书名、作者、价格,销量
*/
private int id;
private String bookName;
private String author;
private double price ;
private int counts;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
return id == book.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public Book() {
}
public Book(int id, String bookName, String author, double price, int counts) {
this.id = id;
this.bookName = bookName;
this.author = author;
this.price = price;
this.counts = counts;
}
@java.lang.Override
public java.lang.String toString() {
return "Book{" +
"id=" + id +
", bookName='" + bookName + '\'' +
", author='" + author + '\'' +
", price=" + price +
", counts=" + counts +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCounts() {
return counts;
}
public void setCounts(int counts) {
this.counts = counts;
}
@Override
public int compareTo(Book o) {
return o.counts-this.counts;
}
}
Hashset
package day21.homework;
import java.util.HashMap;
import java.util.HashSet;
public class HashSetTest {
//添加到一个集合中,要求不可重复,规定编号相同就认为是1本书
// 提示:HashSet
public static void main(String[] args) {
HashSet<Book> lists = new HashSet<>();
lists.add(new Book(1,"天龙八部","金庸",18,120));
lists.add(new Book(3,"倚天屠龙记","金庸",20,130));
lists.add(new Book(2,"火影忍者","mmm",22,222));
lists.add(new Book(1,"天龙八部1","金庸",18,120));
for (Book list : lists) {
System.out.println(list);
}
}
}
Linkedhashset
package day21.homework;
import java.util.LinkedHashSet;
public class LinkedHashSetTest {
//添加到一个集合中,要求不可重复,但是要求按照添加顺序显示
// 提示:LinkedHashSet
public static void main(String[] args) {
LinkedHashSet<Book> lists = new LinkedHashSet<>();
lists.add(new Book(1,"天龙八部","金庸",18,120));
lists.add(new Book(3,"倚天屠龙记","金庸",20,130));
lists.add(new Book(2,"火影忍者","mmm",22,222));
lists.add(new Book(1,"天龙八部","金庸",18,120));
for (Book list : lists) {
System.out.println(list);
}
}
}
Treeset
package day21.homework;
import java.util.Comparator;
import java.util.TreeSet;
public class TestSetTest01 {
/**
* 4、添加到一个集合中,要求不可重复,但是要求这次按照价格从低到高排序
* 提示:TreeSet
*
* 因为在上一题中,默认实现按照销量从高到低,我们就不方便再次修改Book类的compareTo方法
* 说明,Book类的自然排序规则,无法满足本题的要求。
*
* 要求:给TreeSet对象要多传一个“定制比较器对象”,即java.util.Comparator
*
* Arrays.sort(arr):按照元素的自然排序
* Arrays.sort(arr,定制比较器对象)
*
* TreeSet set = new TreeSet();按照元素的自然排序
* TreeSet set = new TreeSet(定制比较器对象);按照定制比较器排序
* @param args
*/
public static void main(String[] args) {
TreeSet<Book> lists = new TreeSet<>(new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
return Double.compare(o1.getPrice(),o2.getPrice());
}
});
lists.add(new Book(1,"天龙八部","金庸",18,120));
lists.add(new Book(3,"倚天屠龙记","金庸",20,130));
lists.add(new Book(2,"火影忍者","mmm",22,222));
lists.add(new Book(1,"天龙八部","金庸",18,120));
for (Book list : lists) {
System.out.println(list);
}
}
}
Treeset01
package day21.homework;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
//添加到一个集合中,要求不可重复,但是要求按照销量从高到低排序
// 提示:TreeSet
TreeSet<Book> lists = new TreeSet<>();
lists.add(new Book(1,"天龙八部","金庸",18,120));
lists.add(new Book(3,"倚天屠龙记","金庸",20,130));
lists.add(new Book(2,"火影忍者","mmm",22,222));
lists.add(new Book(1,"天龙八部","金庸",18,120));
for (Book list : lists) {
System.out.println(list);
}
}
}