目录
1、集合框架的概述
1.1 为什么需要集合框架
我们在java中学习过一个数据类型 --- 数组
数组有问题: 定容 (数组初始化的时候 一旦固定容量 从此就只能存储该容量的数据)
如果我们一旦创建数组 发现数组的容量不够用了 此时就需要扩容 就非常麻烦了。
所以我们自己写了一个类 MyArray getData addData
大家试想一下 你能写?别人也可以写 所以
java官方 就 基于数组 根据不同的数据结构 封装出来了很多的 类 这些类统称为 集合框架
所以说 以后再说到 集合框架 就要想到 里面有很多的类
1.2、集合框架体系
基于数组(底层就是对数组的封装),根据不同的数据结构(列表、集合、数列、映射)产生了很多类
1.2.1单列集合
1.2.2 双列集合
public class MyArray6 {
private Object[] arr; //声明一个Object类型的数组
private int size;//表示数组的下标 行为他们是类成员变量在创建
//时都有默认值
public MyArray6() {//无参构造函数
this(3);//本类中其他的构造函数 this本类的对象。
// 如果在构造方法中this()表示调用本类的其他构造函数
}
public MyArray6(int size) {//有参构造函数---表示数组的长度
if (size < 0) {
throw new RuntimeException("数组长度不合法");//长度不合法抛出异常
}else {
arr = new Object[size];
}
}
//把元素o放入数组arr
public void addDate(Object o) {
//判断你的数组是否已满
if (size >= arr.length) {
//扩容--(1)容器的长度变长 (2)把原来容器中的元素复制到新的容器中
Object[] newArr = Arrays.copyOf(arr, size * 2);
arr = newArr;
}
arr[size] = 0;
size++;
}
//根据下标获取数组中的元素
public Object getDate(int index) {
if (index >= size) {
throw new ArrayIndexOutOfBoundsException("下标越界");
}
Object o = arr[index];
return 0;
}
}
2、List列表
2.1、List特点
有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。
可以简单的理解成和数组的使用方式差不多 , 存储到List中的数据有顺序的 并且可以通过索引编号对其进行操作
public interface List<E> extends Collection<E>
public interface Collection<E> extends Iterable<E>
List接口中声明了一些 常用的增删改查的方法
2.2、ArrayList 快速数组 创建
import java.util.ArrayList;
import java.util.List;
public class JavaTest {
/**
* ArrayList 的创建
*/
@Test
public void test() {
/*创建一个默认容量的 ArrayList */
List haha1 = new ArrayList();
/*自定义初始容量的List创建 */
List haha2 = new ArrayList(666);
}
}
2.3、ArrayList添加数据
public void test1(){
// 有顺序 可以存储null
List haha = new ArrayList<>();
/*追加 */
haha.add("张三");
haha.add("李四");
// add(Object) 666是int类型 为什么能赋值? 自动装箱
haha.add(666);
haha.add(null);
/*插入*/
haha.add(1,"王五");
List hehe = new ArrayList();
hehe.add("java");
hehe.add("html");
hehe.add( haha );
hehe.addAll( haha );
hehe.addAll(0,haha);
//[张三, 王五, 李四, 666, null, java, html, [张三, 王五, 李四, 666, null], 张三, 王五, 李四, 666, null]
System.out.println(hehe);
}
2.4、ArrayList删除数据
public void test2(){
List haha = new ArrayList();
haha.add("张三");
haha.add("lisi");
haha.add("王五");
haha.add("张三");
System.out.println(haha);
/*删除list中某个数据 返回值为 删除的结果 */
boolean remove = haha.remove("张三");
/*根据索引值进行删除 返回值为 被删除的数据 */
Object remove1 = haha.remove(2);
/*清空list中的内容*/
haha.clear();
System.out.println(haha);
}
2.5、ArrayLiay修改数据
public void test3(){
List haha = new ArrayList();
haha.add("张三");
haha.add("lisi");
// 1 先删再加
haha.set(1,"李四");
System.out.println(haha);
}
2.6、ArrayList查询数据
public void test4(){
List haha = new ArrayList(22);
haha.add("张三");
haha.add("李四");
haha.add("李四");
haha.add("李四");
haha.add("王五");
// Returns the number of elements in this list.
//获取长度
int size = haha.size();
System.out.println(size);
// Returns the element at the specified position in this list.
//获取下标为1的元素
Object o = haha.get(1);
System.out.println(o);
// Returns <tt>true</tt> if this list contains no elements.
//判断是否为空
boolean empty = haha.isEmpty();
System.out.println(empty);
// Returns <tt>true</tt> if this list contains the specified element.
//判断是否存在元素lisi
boolean contains = haha.contains("lisi");
System.out.println(contains);
// 将list转换成java数组 Returns an array containing all of the elements in this list in proper
// * sequence (from first to last element).
Object[] objects = haha.toArray();
System.out.println(Arrays.toString(objects));
// Returns the index of the first occurrence(出现) of the specified element in this list, or -1 if this list does not contain the element.
//得到李四的下标
int i1 = haha.indexOf("李四");
int i2 = haha.lastIndexOf("李四");
//遍历得到每个元素 两种方法 for循环 和 for each
for (int i = 0; i < haha.size(); i++) {
Object o1 = haha.get(i);
System.out.println(o1);
}
/* js 中的 for-in */
for (Object o1 : haha) {
System.out.println(o1);
}
}
2.7、ArrayList底层原理
我们要查看底层原理 一般都是从 构造函数开始
在我们调用的时候 new ArrayList<>(66); 在底层其实干了这样的事情
也就是说 ArrayList的底层就是一个 Object 类型的数组 用变量 elementData
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 此时创建了一个 Object类型数组 赋值给了当前的成员变量 elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 如果初始化容量小于零 此时抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
函数 haha.add("asdasd"); 是往list中添加数据 底层就是将数组添加到 elementData这个数组中
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! 扩容
elementData[size++] = e;
return true;
}
ensureCapacityInternal 扩容的函数
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
函数 haha.size() 获取list中有多少个元素 底层就是 返回数组中元素的个数 size是单独定义的变量 每次add的时候都会累加
public int size() {
return size;
}
函数 haha.isEmpty() 获取list中是否有数据 底层就是 判断size变量的值是否为 0
public boolean isEmpty() {
return size == 0;
}
函数 haha.get(1); 获取list中的指定索引位置的数据 底层就是从 elementData中根据索引获取具体的数据
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
函数 haha.indexOf("李四"); 获取在list中首次出现的索引 底层就是 遍历数组 依次查找 返回索引
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
return -1;
}
函数 haha.contains("lisi"); 获取某个元素是否在list中 底层就是
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
函数 haha.set(1,"李四"); 修改指定索引位置的数据 底层就是 修饰数组中某个索引位置的数据
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
3、LinkedList
3.1LinkedList创建
ArrayList 底层体现出来的数据结构是 数组
Linkedlist 底层体现出来的数据结构是 链表
public void test1(){
List haha = new LinkedList();
}
创建了一个 LinkedList 对象 底层构造函数 就是默认的构造函数
3.2LinkedList添加数据
有序 可重复 可为null
public class TestLinkedList {
@SuppressWarnings({"all"})
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add("张三");
linkedList.add("张三");
linkedList.add("李四");
linkedList.add(null);
//元素的批量添加
LinkedList l2 = new LinkedList();
l2.addAll(linkedList);
l2.add("嘿嘿");
l2.add("王五");
l2.add("赵六");
System.out.println(l2);
//在数组的第一个位置 和 最后一个位置添加元素
l2.addFirst("第一个人");
l2.addLast("最后一个人");
l2.push("push");
System.out.println(l2);
}
}
3.3LinkedList删除数据
public class TestLinkedList {
@SuppressWarnings({"all"})
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(4);
linkedList.add(5);
//默认删除第一个元素
Object remove = linkedList.remove();
//根据元素名称进行删除
Object remove1 = linkedList.remove("李四");
//删除第一个元素
Object remove2 = linkedList.remove();
//删除最后一个元素
Object remove3 = linkedList.remove();
//指定元素下标进行删除
Object remove4 = linkedList.remove(0);
System.out.println(linkedList);
}
}
3.3LinkedList数据修改
//根据下标进行修改
Object o = linkedList.set(0, "张三三");//将下标为0的元素修改成“张三三”
Object o1 = linkedList.set(0, "444");//将下标为0的元素修改为“444”
3.4LinkedList数据查看
//查看长度
int size = hehe.size();
//判断是否为空
boolean empty = hehe.isEmpty();
//查看张三的小标
int i = hehe.indexOf("张三");
//判断是否含有李四元素
boolean contains = hehe.contains("李四");
//将hehe转换为数组
Object[] objects = hehe.toArray();
//得到下标为3的元素
Object o = hehe.get(3);
//得到第一个 和 最后一个元素
Object first = hehe.getFirst();
Object last = hehe.getLast();
Object peek = hehe.peek();
Object o1 = hehe.peekFirst();
Object o2 = hehe.peekLast();
3.5、LinkedList的底层源码分析
3.5.1add函数的内部原理
1.凡是查询源码 ,我们都是从类的构造方法入手:
/**
* Constructs an empty list.
*/
public LinkedList() {
}
该类的构造方法内是空的,没有任何的代码。 但是该类中有三个属性。
transient int size = 0; //索引
transient Node<E> first; //第一个元素对象
transient Node<E> last; //表示最后一个元素对象。
================ add的源码=====E:理解为Object类型==========================。
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
//上一个节点 数据 下一个节点
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
==================Node的源码 内部类=======================================
private static class Node<E> { //<E>泛型--object
E item; //数据
Node<E> next; //下一个节点
Node<E> prev; //上一个节点
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
3.5.2get函数内部原理
1、==================== get(1)-----获取元素========================
public E get(int index) {
checkElementIndex(index); //检查index下标是否正确。
return node(index).item; //李四Node对象
}
========================node(index)=============================
Node<E> node(int index) {
//>> 位运算二进制运算 ----- size >> 1 一半的意思size/2
if (index < (size >> 1)) { //前半部分
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else { //后半部分
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
4、Set集合
4.1HashSet集合
4.1.1创建HashSet对象
public class Test02 {
public static void main(String[] args) {
HashSet hashSet= new HashSet();
HashSet hashSet1 = new HashSet(16);//初始容器的大小
//loadFactor:--->0.7f 表示负载因子 当空间使用70%时 要求扩容
HashSet hashSet2 = new HashSet(16,0.7f);
}
}
4.1.2HashSet的添加、删除、修改和遍历
public class Test02 {
public static void main(String[] args) {
//如果没有指定容器的大小 默认为16 负载因子为0.75
HashSet hashSet= new HashSet();
//添加操作
hashSet.add("java01");
hashSet.add("java02");
hashSet.add("java04");
hashSet.add("java03");
hashSet.add("java02");
HashSet set2=new HashSet();
set2.add("刘德华");
set2.add("张学友");
set2.add("黎明");
hashSet.addAll(set2); //把set2中的每个元素添加到hashset中
System.out.println(hashSet); //元素不能重复 而且无序
//删除
hashSet.remove("黎明");
// hashSet.clear();//清空容器集合
System.out.println(hashSet);
//查询操作
boolean empty = hashSet.isEmpty(); //判断是否为空
System.out.println(empty);
boolean b = hashSet.contains("刘德华");//判断元素是否在容器中
System.out.println(b);
//迭代器遍历
Iterator iterator = hashSet.iterator();//获取迭代器对象 有序:有下标
while (iterator.hasNext()){//判断是否指定能够移动
Object next = iterator.next();//指定移动并获取当前的元素
System.out.println(next);
}
//遍历--- foreach
for(Object o: hashSet){
System.out.println(o);
}
}
}
4.2、TreeSet集合
4.2.1 TreeSet集合概念
TreeSet中的方法和HashSet中的方法一模一样 只是他们的实现不一样。
TreeSet 基于TreeMap 实现。TreeSet可以实现有序集合,但是有序性需要通过比较器实现。
4.2.2 存储String类型
TreeSet treeSet=new TreeSet();
treeSet.add("java05");
treeSet.add("java03");
treeSet.add("java04");
treeSet.add("java01");
treeSet.add("java02");
treeSet.add("java04");
System.out.println(treeSet);
4.2.3 存储一个对象类型
public class Test04 {
public static void main(String[] args) {
TreeSet treeSet=new TreeSet();
treeSet.add(new Student("张三",17));
treeSet.add(new Student("李四",16));
treeSet.add(new Student("王五",16));
treeSet.add(new Student("赵六",15));
System.out.println(treeSet);
}
}
通过运行我们发现出现如下的错误:
发现: TreeSet中的元素必须实现Comparable接口 方可放入TreeSet
解决办法有两个:
第一个: 让你的类实现Comparable接口
package com.ykq;
import java.util.TreeSet;
public class Test04 {
public static void main(String[] args) {
TreeSet treeSet=new TreeSet(); //TreeSet不允许重复元素
treeSet.add(new Student("张三",17));
treeSet.add(new Student("李四",16));
treeSet.add(new Student("王五",16));
treeSet.add(new Student("赵六",15));
System.out.println(treeSet);
}
}
class Student implements Comparable{
private String name;
private Integer age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//排序:---返回如果大于0 表示当前元素比o大 如果返回-1 当前添加的元素比o小 返回0表示相同元素。
@Override
public int compareTo(Object o) {
Student student= (Student) o;
System.out.println(this+"===================>"+o);
if(this.age>student.age){
return 1;
}
if(this.age<student.age){
return -1;
}
return 0;
}
}