1、Collection常用方法
package com.example.collection.Collection;import java.util.ArrayList;
import java.util.List;public class Collection03 {public static void main(String[] args) {List list = new ArrayList();//接口可以指向实现该接口的类//add:添加单个元素list.add("lll");list.add(1);//有自动装箱的过程 list.add(new Integer(1));list.add(true);//有自动装箱的过程System.out.println(list);//list里的元素都是对象//remove:删除指定元素 【两种方式】list.remove("111");//指定删除某个元素list.remove(0);//按下标删除第一个元素//contains:查找元素是否存在System.out.println(list.contains("111"));//有返回true,无返回false//size:获取元素个数System.out.println(list.size());//isEmpty:判断是否为空System.out.println(list.isEmpty());//clear:清空list.clear();//addAll:添加多个元素ArrayList list1 = new ArrayList();list1.add("haha");list1.add("3213");list.addAll(list1);System.out.println(list);//containsAll:查找多个元素是否存在System.out.println(list.containsAll(list1));//都存在返回true//removeAll:删除多个元素list.removeAll(list1);}}
2、迭代器遍历
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));//System.out.println("col=" + col);//现在希望能够遍历 col集合//1. 先得到 col 对应的 迭代器Iterator iterator = col.iterator();//2. 使用while循环遍历
// while (iterator.hasNext()) {//判断是否还有数据
// //返回下一个元素,类型是Object
// Object obj = iterator.next();
// System.out.println("obj=" + obj);
// }//一个快捷键,快速生成 while => itit//显示所有的快捷键的的快捷键 ctrl + jwhile (iterator.hasNext()) {Object obj = iterator.next();System.out.println("obj=" + obj);}//3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素// iterator.next();//NoSuchElementException//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;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +'}';}
}
3、增强for遍历
增强for循环,可以代替iterator迭代器,特点:增强for就是简化本的iterator,本质一样。只能用于遍历集合或数组。
public class CollectionFor {@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. 使用增强for, 在Collection集合//2. 增强for, 底层仍然是迭代器//3. 增强for可以理解成就是简化版本的 迭代器遍历//4. 快捷键方式 I
// for (Object book : col) {
// System.out.println("book=" + book);
// }for (Object o : col) {System.out.println("book=" + o);}//增强for,也可以直接在数组使用
// int[] nums = {1, 8, 10, 90};
// for (int i : nums) {
// System.out.println("i=" + i);
// }}
}
4、 List接口和常用方法
(1)List接口基本介绍
List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复;
public class List_ {@SuppressWarnings({"all"})public static void main(String[] args) {//1. List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]List list = new ArrayList();list.add("jack");list.add("tom");list.add("mary");list.add("hsp");list.add("tom");System.out.println("list=" + list);//2. List集合中的每个元素都有其对应的顺序索引(即一个整数型的序号记载//其在容器中的文字hi,可以根据序号存取容器中的元素),即支持索引。// 索引是从0开始的System.out.println(list.get(3));//hsp}
}
(2)List接口的常用方法
① void add(int index, Object ele):在index位置插入ele元素,没有index,默认在最后插入
② boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
③ Object get(int index):获取指定index位置的元素
④ int indexOf(Object obj):返回obj在集合中首次出现的位置
⑤ int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
⑥ Object remove(int index):移除指定index位置的元素,并返回此元素
⑦ Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
⑧ List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合,注意返回的子集合 fromIndex <= subList < toIndex
public class ListMethod {@SuppressWarnings({"all"})public static void main(String[] args) {List list = new ArrayList();list.add("张三丰");list.add("贾宝玉");
// void add(int index, Object ele):在index位置插入ele元素//在index = 1的位置插入一个对象list.add(1, "韩顺平");System.out.println("list=" + list);
// 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);
// 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 < toIndexList returnlist = list.subList(0, 2);System.out.println("returnlist=" + returnlist);}
}
(3)List的三种遍历方式
ArrayList, LinkedList,Vector三种遍历使用的方式一致。
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. 增强forfor (Object o : list) {System.out.println("o=" + o);}System.out.println("=====普通for====");//3. 使用普通forfor (int i = 0; i < list.size(); i++) {System.out.println("对象=" + list.get(i));}}
}
(4)ArrayList 的注意事项
(1)permits all elements,including null,ArrayList可以加入null,并且可以有多个;
(2)ArrayList 是由数组来实现数据存储的;
(3)ArrayList 基本等同于Vector,除了ArrayList是线程不安全的(但执行效率高),在多线程情况下,不建议使用ArrayList。
(5)ArrayList 底层结构和源码分析🚩🚩
① ArrayList中维护了一个object类型的数组elementData;
transient Object[] elementData;//transient 表示瞬间,短暂的,表示该属性不能被序列号;
② 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次田间,则扩容elementData为10,如果需要再次扩容,则扩容elementData为1.5倍;
@SuppressWarnings({"all"})
public class ArrayListSource {public static void main(String[] args) {//解读源码//注意,注意,注意,Idea 默认情况下,Debug 显示的数据是简化后的,如果希望看到完整的数据//需要做设置.//使用无参构造器创建ArrayList对象ArrayList list = new ArrayList();//ArrayList list = new ArrayList(8);//使用for给list集合添加 1-10数据for (int i = 1; i <= 10; i++) {list.add(i);}//使用for给list集合添加 11-15数据for (int i = 11; i <= 15; i++) {list.add(i);}list.add(100);list.add(200);list.add(null);}
}
③ 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
@SuppressWarnings({"all"})
public class ArrayListSource {public static void main(String[] args) {//解读源码//注意,注意,注意,Idea 默认情况下,Debug 显示的数据是简化后的,如果希望看到完整的数据//需要做设置.//使用无参构造器创建ArrayList对象//ArrayList list = new ArrayList();ArrayList list = new ArrayList(8);//使用for给list集合添加 1-10数据for (int i = 1; i <= 10; i++) {list.add(i);}//使用for给list集合添加 11-15数据for (int i = 11; i <= 15; i++) {list.add(i);}list.add(100);list.add(200);list.add(null);}
}
5、Vector底层结构和源码剖析
(1)Vector的基本介绍
① Vector底层是一个对象数组,protected Object[] elementData;
② Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized;
③ 开发中,需要线程同步安全时,考虑使用Vector。
(2)Vector 和 ArrayList 的比较
(3)Vector的底层扩容结构
@SuppressWarnings({"all"})
public class Vector_ {public static void main(String[] args) {//无参构造器//有参数的构造Vector vector = new Vector(8);for (int i = 0; i < 10; i++) {vector.add(i);}vector.add(100);System.out.println("vector=" + vector);//老韩解读源码//1. new Vector() 底层/*public Vector() {this(10);}补充:如果是 Vector vector = new Vector(8);走的方法:public Vector(int initialCapacity) {this(initialCapacity, 0);}2. vector.add(i)2.1 //下面这个方法就添加数据到vector集合public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;}2.2 //确定是否需要扩容 条件 : minCapacity - elementData.length>0private void ensureCapacityHelper(int minCapacity) {// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}2.3 //如果 需要的数组大小 不够用,就扩容 , 扩容的算法//newCapacity = oldCapacity + ((capacityIncrement > 0) ?// capacityIncrement : oldCapacity);//就是扩容两倍.private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);}*/}
}
6、LinkedList 底层结构
① LinkedList的说明
a LinkedList底层实现了双向链表和双端队列的特点;
b 可以添加任意元素(元素可以重复),包括null;
c 线程不安全,没有实现同步。
② LinkedList的底层操作机制
a LinkedList底层维护了一个双向链表;
b LinkedList中维护了两个属性first 和 last 分别指向首节点和尾节点;
c 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表;
d 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率比较高;
e 模拟一个简单的双向链表。
public class LinkedList01 {public static void main(String[] args) {//模拟一个简单的双向链表Node jack = new Node("jack");Node tom = new Node("tom");Node hsp = new Node("老韩");//连接三个结点,形成双向链表//jack -> tom -> hspjack.next = tom;tom.next = hsp;//hsp -> tom -> jackhsp.pre = tom;tom.pre = jack;Node first = jack;//让first引用指向jack,就是双向链表的头结点Node last = hsp; //让last引用指向hsp,就是双向链表的尾结点//演示,从头到尾进行遍历System.out.println("===从头到尾进行遍历===");while (true) {if(first == null) {break;}//输出first 信息System.out.println(first);first = first.next;}//演示,从尾到头的遍历System.out.println("====从尾到头的遍历====");while (true) {if(last == null) {break;}//输出last 信息System.out.println(last);last = last.pre;}//演示链表的添加对象/数据,是多么的方便//要求,是在 tom --------- 老韩直接,插入一个对象 smith//1. 先创建一个 Node 结点,name 就是 smithNode smith = new Node("smith");//下面就把 smith 加入到双向链表了smith.next = hsp;smith.pre = tom;hsp.pre = smith;tom.next = smith;//让first 再次指向jackfirst = jack;//让first引用指向jack,就是双向链表的头结点System.out.println("===从头到尾进行遍历===");while (true) {if(first == null) {break;}//输出first 信息System.out.println(first);first = first.next;}last = hsp; //让last 重新指向最后一个结点//演示,从尾到头的遍历System.out.println("====从尾到头的遍历====");while (true) {if(last == null) {break;}//输出last 信息System.out.println(last);last = last.pre;}}
}//定义一个Node 类,Node 对象 表示双向链表的一个结点
class Node {public Object item; //真正存放数据public Node next; //指向后一个结点public Node pre; //指向前一个结点public Node(Object name) {this.item = name;}public String toString() {return "Node name=" + item;}
}
③ 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));}//源码阅读./* 1. LinkedList linkedList = new LinkedList();public LinkedList() {}2. 这时 linkeList 的属性 first = null last = null3. 执行 添加public boolean add(E e) {linkLast(e);return true;}4.将新的结点,加入到双向链表的最后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;elsel.next = newNode;size++;modCount++;}*//*读源码 linkedList.remove(); // 这里默认删除的是第一个结点1. 执行 removeFirstpublic E remove() {return removeFirst();}2. 执行public E removeFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return unlinkFirst(f);}3. 执行 unlinkFirst, 将 f 指向的双向链表的第一个结点拿掉private E unlinkFirst(Node<E> f) {// assert f == first && f != null;final E element = f.item;final Node<E> next = f.next;f.item = null;f.next = null; // help GCfirst = next;if (next == null)last = null;elsenext.prev = null;size--;modCount++;return element;}*/}
}
7、ArrayList 和 LinkedList 比较
如何选择 ArrayList和ListedList:
① 如果我们改查的操作多,选择ArrayList;
② 如果我们增删的操作多,选择ListedList;
③ 一般来说,在程序中,80-90%都是查询,大部分情况下会选择ArrayList;
④ 在项目中,会根据业务灵活选择,可能一个模块用ArrayList,另一个用ListedList。