一、基本概念
1.可以动态保存任意多个对象,使用方便
2.提供了一系列方便操作对象的方法:add、remove、set、get等
3.使用集合添加,删除新元素的代码简洁
(1)、集合的框架体系
java的集合类很多,主要分为两大类:Collection和Map。
1.集合主要是两组(单列集合,双列集合)
2.Collection接口有两个重要的子接口,List和Set,它们的实现子类都是单列集合
3.Map接口的实现子类是双列集合,存放的K-V
二、Collection接口
(1)、常用方法
(1)Collection实现子类可以存放多个元素,每个元素可以是Object
(2)Collection的有些实现类,可以存放重复的元素,有些不可以
(3)Collection的有些实现类,有些是有序的(List),有些不是有序(Set)
(4)Collection接口没有直接的实现子类,是通过它的子接口Set 和 List 来实现的
以下代码演示Collection实现类的常用方法
import java.util.ArrayList;
import java.util.List;
public class CollectionMethod {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList();
// 1.add:添加单个元素
list.add("jack");
list.add(10);//list.add(new Integer(10))
list.add(true);
System.out.println("list=" + list);
// 2.remove:删除指定元素
//list.remove(0);//删除第一个元素
list.remove(true);//指定删除某个元素
System.out.println("list=" + list);
// 3.contains:查找元素是否存在
System.out.println(list.contains("jack"));//T
// 4.size:获取元素个数
System.out.println(list.size());//2
// 5.isEmpty:判断是否为空
System.out.println(list.isEmpty());//F
// 6.clear:清空
list.clear();
System.out.println("list=" + list);
// 7. addAll:添加多个元素
ArrayList list2 = new ArrayList();
list2.add("红楼梦");
list2.add("三国演义");
list.addAll(list2);
System.out.println("list=" + list);
// 8.containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));//T
// 9.removeAll:删除多个元素
list.add("聊斋");
list.removeAll(list2);
System.out.println("list=" + list);//[聊斋]
// 说明:以ArrayList实现类来演示.
}
}
(2)、Collection接口遍历元素方式
1.Iterator迭代器
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
所有实现了Collection接口的集合类都有一个itertor()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
Iterator仅用于遍历结合,Iterator本身并不存放对象。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionIterator {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(new Book("三国演义", "罗贯中", 10.1));
col.add(new Book("小李飞刀", "古龙", 5.1));
col.add(new Book("红楼梦", "曹雪芹", 34.6));
//1. 先得到 col 对应的 迭代器
Iterator iterator = col.iterator();
//2. 使用while循环遍历
while (iterator.hasNext()) {//判断是否还有数据
//返回下一个元素,类型是Object
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
//快捷键,快速生成 while => itit
//显示所有的快捷键的的快捷键 ctrl + j
//3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素
//4. 如果希望再次遍历,需要重置我们的迭代器
iterator = col.iterator();
System.out.println("===第二次遍历===");
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
}
}
class Book {
private String name;
private String author;
private double price;
public Book(String name, String author, double price) {
this.name = name;
this.author = author;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
2、增强for循环
增强for循环,可以代替iterator选代器,特点:增强for就是简化版的iterator本质一样。只能用于遍历集合或数组。
基本语法
for(元素类型 元素名:集合名或数组名){访问元素
}
for (object object : col){System.out.printin(object);
}
遍历时,每个元素都是Object类型
for (Object o : col) { System.out.println("book=" + o); }
三、List接口和常用方法
(1)List 接口是 Collection 接囗的子接口
(2)List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
(3)List集合中的每个元素都有其对应的顺序索引,即支持索引。
(4)List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
常用的有:AyyayList、LinkedList和Vector
(1).List接口的常用方法
import java.util.ArrayList;
import java.util.List;
public class ListMethod {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
// 1.void add(int index, Object ele):在index位置插入ele元素
//在index = 1的位置插入一个对象
list.add(1, "韩顺平");
System.out.println("list=" + list);
// 2.boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1, list2);
System.out.println("list=" + list);
// 3.Object get(int index):获取指定index位置的元素
// int indexOf(Object obj):返回obj在集合中首次出现的位置
System.out.println(list.indexOf("tom"));//2
// int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
list.add("韩顺平");
System.out.println("list=" + list);
System.out.println(list.lastIndexOf("韩顺平"));
// Object remove(int index):移除指定index位置的元素,并返回此元素
list.remove(0);
System.out.println("list=" + list);
// Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
list.set(1, "玛丽");
System.out.println("list=" + list);
// List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
// 注意返回的子集合 fromIndex <= subList < toIndex
List returnlist = list.subList(0, 2);
System.out.println("returnlist=" + returnlist);
}
}
(2).List的三种遍历方式
方式一:使用iterator
Iterator iter = col.iterator();
while(iter.hasNext()){ Object o = iter.next();
}
2)方式二:使用增强forfor(object o:col){}
3)方式三:使用普通forforint i=0;i<list.size();i+ +){Object object = list.get(i);
System.out.println(object);
}
说明:使用LinkedList完成 使用方式和ArrayList 一样
import java.util.*;
public class ListFor {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//List 接口的实现子类 Vector LinkedList
//List list = new ArrayList();
//List list = new Vector();
List list = new LinkedList();
list.add("jack");
list.add("tom");
list.add("鱼香肉丝");
list.add("北京烤鸭子");
//遍历
//1. 迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println("=====增强for=====");
//2. 增强for
for (Object o : list) {
System.out.println("o=" + o);
}
System.out.println("=====普通for====");
//3. 使用普通for
for (int i = 0; i < list.size(); i++) {
System.out.println("对象=" + list.get(i));
}
}
}
例题:使用List的实现类添加三本图书,并按照价格排序,从低到高(使用冒泡排序)
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
@SuppressWarnings({"all"})
public class ListExercise02 {
public static void main(String[] args) {
//List list = new ArrayList();
List list = new LinkedList();
//List list = new Vector();
list.add(new Book("红楼梦", "曹雪芹", 100));
list.add(new Book("西游记", "吴承恩", 10));
list.add(new Book("水浒传", "施耐庵", 19));
list.add(new Book("三国", "罗贯中", 80));
//冒泡排序
sort(list);
System.out.println("==排序后==");
for (Object o : list) {
System.out.println(o);
}
}
//静态方法
//价格要求是从小到大
public static void sort(List list) {
int listSize = list.size();
for (int i = 0; i < listSize - 1; i++) {
for (int j = 0; j < listSize - 1 - i; j++) {
//取出对象Book,
//取出的是Object类型,需要强制类型转化为Book类型
Book book1 = (Book) list.get(j);
Book book2 = (Book) list.get(j + 1);
if (book1.getPrice() > book2.getPrice()) {//交换
list.set(j, book2);
list.set(j + 1, book1);
}
}
}
}
}
***上述代码中的Book类型可以查看上面迭代器展示时的代码示例中的Book类型
(3)ArrayList底层结构和源码分析
1.ArrayList的注意事项
(1)permits all elements, including null ,ArrayList 可以加入null,并且多个
(2)ArrayList 是由数组来实现数据存储的
(3)ArrayList 基本等同于Vector,除了 ArrayList是线程不安全(执行效率高) 看源码在多线程情况下,不建议使用ArrayList
2.ArrayList的底层操作机制
(1)ArrayList中维护了一个Object类型的数组elementData
transient Object[l elementData; //transient 表示瞬间,短暂的, 表示该属性不会被序列号
(2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容则直接扩容elementData为1.5倍。
源代码演示扩容机制
(4)Vector的底层操作机制
1.Vector底层也是一个对象数组,
2.Vector是线程同步的,即线程安全的,Vector类的操作方法带有synchronized
3.在开发中,需要线程同步安全时,考虑使用Vector
(5)Vector和ArrayList的比较
(6)LinkedList底层结构
(1)LinkedList底层实现了双向链表和双端队列特点
(2)可以添加任意元素(元素可以重复),包括null
(3)线程不安全,没有实现同步
(4)LinkedList底层维护了一个双向链表,
(5)LinkedList中维护了两个属性first和last分别指向 首节点和尾节点
(6)每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一 个,通过next指向后一个节点。最终实现双向链表.
(7)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。5)模拟一个简单的双向链表
LinkedList的增删查改
import java.util.Iterator;
import java.util.LinkedList;
@SuppressWarnings({"all"})
public class LinkedListCRUD {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
System.out.println("linkedList=" + linkedList);
//演示一个删除结点的
linkedList.remove(); // 这里默认删除的是第一个结点
//linkedList.remove(2);
System.out.println("linkedList=" + linkedList);
//修改某个结点对象
linkedList.set(1, 999);
System.out.println("linkedList=" + linkedList);
//得到某个结点对象
//get(1) 是得到双向链表的第二个对象
Object o = linkedList.get(1);
System.out.println(o);//999
//因为LinkedList 是 实现了List接口, 遍历方式
System.out.println("===LinkeList遍历迭代器====");
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println("next=" + next);
}
System.out.println("===LinkeList遍历增强for====");
for (Object o1 : linkedList) {
System.out.println("o1=" + o1);
}
System.out.println("===LinkeList遍历普通for====");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
}
}
(7)ArrayList和LinkedList的比较分析
四、Set接口和常用方法
(1)Set接口基本介绍
1.无序(添加和取出的顺序不一致),没有索引
2不允许重复元素,所以最多包含一个null
3.和List接口一样,Set接口也是Collection的子接口,因此常用方法和Collection接口一样
4.取出Set时,取出的顺序虽然不是添加的顺序,但也是固定的顺序(即多次取出的顺序是一致的)
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@SuppressWarnings({"all"})
public class SetMethod {
public static void main(String[] args) {
//老韩解读
//1. 以Set 接口的实现类 HashSet 来讲解Set 接口的方法
//2. set 接口的实现类的对象(Set接口对象), 不能存放重复的元素, 可以添加一个null
//3. set 接口对象存放数据是无序(即添加的顺序和取出的顺序不一致)
//4. 注意:取出的顺序的顺序虽然不是添加的顺序,但是他的固定.
Set set = new HashSet();
set.add("john");
set.add("lucy");
set.add("john");//重复
set.add("jack");
set.add("mary");
set.add(null);//
set.add(null);//再次添加null
for(int i = 0; i <10;i ++) {
System.out.println("set=" + set);
}
//遍历
//方式1: 使用迭代器
System.out.println("=====使用迭代器====");
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
set.remove(null);
//方式2: 增强for
System.out.println("=====增强for====");
for (Object o : set) {
System.out.println("o=" + o);
}
//set 接口对象,不能通过索引来获取
}
}
(2)HashSet的全面说明
(1)HashSet实现了Set接口
(2)Hashset实际上是HashMap,
public Hashset(){map = new HashMap<>();
(3)可以存放null值,但是只能有一个null
(4) HashSet不保证元素是有序的,取决于hash后,再确定索引的结果。(即,不保证存放元素的顺序和取出顺序一致)(5)不能有重复元素/对象.在前面Set 接口使用已经讲过
(3)HashSet的底层机制
1HashSet 底层是 HashMap
2.添加一个元素时,先得到hash值 -会转成->索引值
3.找到存储数据表table,看这个索引位置是否已经存放的有元素
4.如果没有,直接加入
5.如果有 ,调用 equals 比较,如果相同,就放弃添加,如果不相同,则添加到最后
6.在Java8中,如果一条链表的元素个数到达 TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)
7.HashSet底层是HashMap,第一次添加时,table 数组扩容到 16,1临界值(threshold)是 16*加载因子(loadFactor)是0.75=12
8.如果table 数组使用到了临界值 12,就会扩容到 16*2=32,新的临界值就是32*0.75 =24,依次类推
9.在Java8中,如果一条链表的元素个数到达 TREEIFY THRESHOLD(默认是 8),并且table的大小 >=MIN TREEIFY CAPACITY(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制
以上内容为集合中的部分内容,后续内容会在接下来的博客中继续更新