一、集合是什么?
Java集合类存放于 java.util 包中,是一个用来存放对象的容器。
注意:①、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。
②、集合存放的是多个对象的引用,对象本身还是放在堆内存中。
③、集合可以存放不同类型,不限数量的数据类型。
Collection是最基本的集合接口,一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。
2、Iterable 和 Iterator 的区别
1. 两者都是接口,Iterable位于java.lang包下,Iterator位于java.util包下,两者之间的关系是Iterable接口提供了一个获取Iterator接口实例的方法。
2. Iterator是迭代器,如果一个对象拥有迭代器,那么就可以将对象中的所有元素和内容遍历出来,所以所有实现了Iterable接口的所有类都拥有迭代器Iterator。
3. Collection 接口 继承 Iterable接口(Java集合的顶层接口)(不包括 map 系列的集合,Map接口 是 map 系列集合的顶层接口)
迭代器Iterator 的方法:
Object next():返回迭代的下一个元素。,返回值是 Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
ListIterator相对Iterator增加了如下3个方法:
boolean hasPrevious():返回该迭代器关联的集合是否还有上一个元素。
Object previous():返回该迭代器的上一个元素。
void add():在指定位置插入一个元素。
public class Test {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//迭代器遍历
//遍历原理:得到迭代器-->是否有下一个元素-->如果有就返回下一个元素.
Iterator it = list.iterator();
while(it.hasNext()){ //hasNext()判断是否存在下一个元素
Object next = it.next(); //返回迭代的下一个元素。
System.out.print(next); //abcd
}
// 单项迭代器就是单项迭代器
Iterator it2 = list.iterator();
while(it2.hasNext()){
// 在迭代器中使用 list 直接添加或删除元素, 报 运行时修改异常 ConcurrentModificationException
//list.add(3);
//list.remove("a");
// 但是set方法却不报错,因为指针没有移动
//list.set(3, "我set方法却不报错,哈哈");
System.out.print(it2.next()); //abcd
如果:这里加入:it2.remove(); 遍历一个删一个,最后list集合里面的全没了。
}
it2.remove(); // 从迭代器指向的 collection集合 中移除迭代器返回的最后一个元素
//双向迭代遍历 interface ListIterator<E> extends Iterator<E>
// 双向迭代器可以从前向后迭代,同时也可以从后向前迭代,
// 在API中是用ListIterator来实现的,该接口继承Iterator接口
ListIterator listIt=list.listIterator();//获得列表迭代器,扩展了Iterator接口
while(listIt.hasNext()){//向后遍历
System.out.print(listIt.next()); //abc
listIt.add(" 我可以用耶 ");
}
System.out.println("=======下面开始反向迭代=======");
while(listIt.hasPrevious())//返回该迭代器关联的集合是否还有上一个元素。
{//返回该迭代器的上一个元素。
System.out.print(listIt.previous());// 我可以用耶 c 我可以用耶 b 我可以用耶 a
}
}
}
3.面试题:ArrayList和LinkedList的关系和区别?
1.原理不一样 ArrayList基于数组,改查快, 添删慢 ;LinkedList基于链表实现,添加删除快 查询修改慢
2.两者都是集合框架中的容器,可以存储重复的数据,都是List接口的实现类
3.LinkedList可以用来模拟队列以及堆栈的数据结构
4.LinkedList相对于ArrayList多了很多的方法,其实操作链表的头部和尾部的一些方法
4. Queue [kju:] 和 Deque ['dek]
结构:Queue和Deque都是接口,Deque接口继承Queue接口,LinkedList是Deque的实现类。
- Queue表示一种队列,也是一种数据结构,它的特点是先进先出,因此在队列这个接口里面提供了一些操作队列的方法,同时LinkedList也具有这些方法;
- Deque(Double ended queues双端队列),支持在两端插入或者移除元素; 那也应该具有操作双端队列的一些方法;
- LinkedList是他们的子类,说明都具有他们两者的方法;LinkedList也可以充当队列,双端队列,堆栈多个角色;
5 .ArrayList类的常用方法
每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。默认初始容量为10。随着ArrayList中元素的增加,它的容量也会不断的自动增长。在每次添加新的元素时,ArrayList都会检查是否需要进行扩容操作,扩容操作带来数据向新数组的重新拷贝,所以如果我们知道具体业务数据量,在构造ArrayList时可以给ArrayList指定一个初始容量,这样就会减少扩容时数据的拷贝问题。当然在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
注意,ArrayList实现不是同步的。ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。
List list = Collections.synchronizedList(new ArrayList(...));
——ArrayList 线程不安全,查询速度快
——Vector 线程安全,但速度慢,已被ArrayList替代
——LinkedList 链表结果,增删速度快
package ArrayList类的常用方法;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
/*构造方法: 1. ArrayList() 构造一个初始容量为10的空列表,这是最常用的构造方法
2. ArrayList(Collection<? extends E> c)
构造一个包含指定 collection 的元素的列表,这些元素是按照该collection的迭代器返回它们的顺序排列的
3. ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。
*/
/*//1. 增: 4个方法:
// 1.1 add(E e):将指定的元素添加到此列表的尾部。
// 1.2 add(int index, E element):将指定的元素插入此列表中的指定位置。
// 1.3 addAll(Collection<? extends E> c):按照指定 collection的迭代器所返回的元素顺序,
// 将该 collection中的所有元素添加到此列表的尾部。
// 1.4 addAll(int index, Collection<? extends E> c):从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。
*/
//案例:
ArrayList list = new ArrayList();
list.add(5);
list.add(2);
list.add(2, '你');//将置顶元素添加到指定位置(插入算法)
System.out.println(list); //[5, 2, 你]
ArrayList list2 = new ArrayList();
list2.add("13");
list2.add("14");
list2.add("呀");
list.addAll(list2);
System.out.println(list); //[5, 2, 你, 13, 14, 呀]
list.addAll(2, list2);
System.out.println(list); //[5, 2, 13, 14, 呀, 你, 13, 14, 呀]
list.set(5, "你好呀");
System.out.println(list); //[5, 2, 13, 14, 呀, 你好呀, 13, 14, 呀]
/* 2. 删: 4个方法:
// 2.1 clear() 移除此列表中的所有元素。
// 2.2 remove(int index):移除此列表中指定位置上的元素。
// 2.3 remove(Object o):移除此列表中首次出现的指定元素(如果存在)。
// 2.4 removeAll():移除此 collection 中那些也包含在指定 collection 中的所有元素
*/
// 案例:
list.remove(2);
list.remove("14");
System.out.println(list); // [5, 2, 呀, 你好呀, 13, 14, 呀]
list.removeAll(list2);
System.out.println(list); //[5, 2, 你好呀]
list.clear();
System.out.println(list); //[]
/*3. 改:
3.1 set(int index, E element):用指定的元素替代此列表中指定位置上的元素。
3.2 ensureCapacity(int minCapacity) 增加此 ArrayList 实例的容量,手动扩容
3.3 trimToSize() 将此 ArrayList 实例的容量调整为列表的当前大小 .
比如最开始容器大小为100,后来发现容器只添加了5个,就可以使用该方法,调整为只有5个元素的容器
*/ //案例:
ArrayList list3 = new ArrayList(50);
list3.add("你好");
list3.add("我好");
list3.add("大家好");
list3.set(2, "enen");
System.out.println(list3); //[你好, 我好, enen]
list3.ensureCapacity(40);
System.out.println(list3.size()); //3
list3.trimToSize();
/*4. 查:
4.1 size() 返回此列表中的元素数。
4.2 get(int index) 返回此列表中指定位置上的元素
4.3 indexOf(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1
4.4 lastIndexOf(Object o) 返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。
*/
System.out.println(list3.get(1)); //我好
System.out.println(list3.indexOf("我好")); //1
/*5. 其他方法
*/ System.out.println(list.isEmpty()); //true
System.out.println(list3.contains("我好")); //true
// Object[] toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组
System.out.println(Arrays.toString(list3.toArray())); //[你好, 我好, enen]
}
}
6.LinkedList类的常用方法
首先我们先看LinkedList的定义:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
从这段代码中我们可以清晰地看出LinkedList继承AbstractSequentialList,实现List、Deque、Cloneable、Serializable。其中AbstractSequentialList提供了 List 接口的骨干实现,从而最大限度地减少了实现受“连续访问”数据存储(如链接列表)支持的此接口所需的工作,从而以减少实现List接口的复杂度。Deque一个线性 collection,支持在两端插入和移除元素,定义了双端队列的操作。
package LinkedList类的常用方法;
import java.util.AbstractSequentialList;
import java.util.Deque;
import java.util.List;
public class Test {
public static void main(String[] args) {
// LinkedList<E> extends AbstractSequentialList<E>
// implements List<E>, Deque<E>, Cloneable, java.io.Serializable
//1. 构造方法:
/* 1.1 LinkedList()空参构造,仅仅只是将header节点的前一个元素、后一个元素都指向自身。
public LinkedList() {
header.next = header.previous = header;
}
1.2 LinkedList(Collection<? extends E> c)
构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列。
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
*/
//2. 两个字段 : size表示的LinkedList的大小,header表示链表的表头
//Entry为节点对象。
/* private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
*/
//3. 常用方法 LinkedList的方法和ArrayList差不多,因为他们都实现了List接口,在List接口中已经定义了大部分的共有方法,
//由于LinkedList使用的数据结构是链表方式,所以在有些方法上有些差别,差别在于可以在容器的头部和尾部对元素做操作:
下面介绍LinkedList实现Deque接口的方法
public class Test {
public static void main(String[] args) {
Deque<Integer> deq = new LinkedList();
deq.add(1);
deq.add(2);
deq.add(3);
deq.add(4);
deq.add(5);
System.out.println(deq); // [1, 2, 3, 4, 5]
//1. peek()和element()方法 都是获取(不移除此双端队列)队列的头部
// 区别:peek(),如果链表为空,则返回null。element(),如果链表为空,则抛异常。
System.out.println(deq.peek()); // 1
System.out.println(deq.element()); // 1
//2. peekFirst() 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
// peekLast() 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
System.out.println(deq.peekFirst()); //1
System.out.println(deq.peekLast()); //5
//3. poll() pop() 获取并移除此列表的头(第一个元素) pop()出栈 push压栈
// poll()和 pop()区别: 如果此列表为空,pop()抛出NoSuchElementException,poll()则返回 null
System.out.println(deq.poll()); //1
System.out.println(deq); //[2, 3, 4, 5]
System.out.println(deq.pop()); //2
System.out.println(deq); //[3, 4, 5]
//4. pollFirst() 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
// pollLast() 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
System.out.println(deq.pollFirst()); //3
System.out.println(deq.pollLast()); //5
//5 push(E e) 将元素推入此列表所表示的堆栈 ,
// 如果成功,则返回 true,如果当前没有可用空间,则抛出 IllegalStateException。
deq.push(520131);
System.out.println(deq); //[520131, 4]
}
}
7.HashSet类的常用方法
HashSet堪称查询速度最快的集合,因为其内部是以HashCode来实现的。
它内部元素的顺序是由哈希码来决定的,所以它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。
package HashSet类的常用方法;
import java.util.AbstractSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test3 {
public static void main(String[] args) {
//继承关系: class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
/*1. 字段
//基于HashMap实现,底层使用HashMap保存所有元素
private transient HashMap<E,Object> map;
//定义一个Object对象作为HashMap的value
private static final Object PRESENT = new Object();
*/
/*2. 构造方法
2.1//初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。
public HashSet() {
map = new HashMap<>();
}
2.2// 构造一个包含指定 collection 中的元素的新 set。
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
2.3//构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
2.4//构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
2.5 在API中我没有看到这个构造函数,今天看源码才发现(原来访问权限为包权限,不对外公开的)
* 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。
* dummy 为标识 该构造函数主要作用是对LinkedHashSet起到一个支持作用
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
*/
/*3.普通方法
* 前言:HashSet的方法和ArrayList的方法大同小异,差别在于:
HashSet是无序的,所以涉及到index索引的方法在HashSet里面都没有.
*/
HashSet set1 = new HashSet();
HashSet set2 = new HashSet();
for (int i = 0; i < 4; i++) {
set1.add(i); //[0, 1, 2, 3]
}
for (int i = 2; i < 6; i++) {
set2.add(i); //[2, 3, 4, 5]
}
set1.add(set2);
System.out.println(set1); //[0, 1, 2, 3, [2, 3, 4, 5]]
set1.addAll(set2);
System.out.println(set1); //[0, 1, 2, 3, 4, 5, [2, 3, 4, 5]]
//迭代器遍历
Iterator iterator = set1.iterator();
while(iterator.hasNext()){
Object next = iterator.next();
System.out.print(next); //012345[2, 3, 4, 5]
}
System.out.println(set1.contains(3)); //true
set1.remove(set2);
System.out.println(set1); //[0, 1, 2, 3, 4, 5]
set1.clear();
System.out.println(set1); //[]
}
}
8.TreeSet类的常用方法
在TreeSet中默认要求里面的元素进行自然排序,强制要求里面的所有元素必须按照Comparable中的compareTo方法进行比较,如果容器里面的对象不具备compareTo方法此时就会抛出异常报错。
所以必须要让容器中的元素实现Comparable接口,这样它才具备compareTo方法。
1.TreeSet实例在调用add方法时会调用容器对象的compareTo方法对元素进行比较
2.TreeSet实例中对象必须是实现了Comparable接口
package TreeSet类的常用方法;
public class Test4 {
public static void main(String[] args) {
//1.继承关系
/* public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
*/
//2.变量
/* private transient NavigableMap<E,Object> m;
//PRESENT会被当做Map的value与key构建成键值对
private static final Object PRESENT = new Object();
*/
//3.构造方法
/* //3.1默认构造方法,根据其元素的自然顺序进行排序
public TreeSet() {
this(new TreeMap<E,Object>());
}
//3.2构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
//3.3构造一个新的空 TreeSet,它根据指定比较器进行排序。
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
//3.4构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet。
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
//3.5
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
*/
//4.主要方法
/* 1、add:将指定的元素添加到此 set(如果该元素尚未存在于 set 中)。
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
2、addAll:将指定 collection 中的所有元素添加到此 set 中。
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT);
return true;
}
}
return super.addAll(c);
}
3、ceiling:返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null。
public E ceiling(E e) {
return m.ceilingKey(e);
}
4、clear:移除此 set 中的所有元素。
public void clear() {
m.clear();
}
5、clone:返回 TreeSet 实例的浅表副本。属于浅拷贝。
public Object clone() {
TreeSet<E> clone = null;
try {
clone = (TreeSet<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
clone.m = new TreeMap<>(m);
return clone;
}
6、comparator:返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回 null。
public Comparator<? super E> comparator() {
return m.comparator();
}
7、contains:如果此 set 包含指定的元素,则返回 true。
public boolean contains(Object o) {
return m.containsKey(o);
}
8、descendingIterator:返回在此 set 元素上按降序进行迭代的迭代器。
public Iterator<E> descendingIterator() {
return m.descendingKeySet().iterator();
}
9、descendingSet:返回此 set 中所包含元素的逆序视图。
public NavigableSet<E> descendingSet() {
return new TreeSet<>(m.descendingMap());
}
10、first:返回此 set 中当前第一个(最低)元素。
public E first() {
return m.firstKey();
}
11、floor:返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null。
public E floor(E e) {
return m.floorKey(e);
}
12、headSet:返回此 set 的部分视图,其元素严格小于 toElement。
public SortedSet<E> headSet(E toElement) {
return headSet(toElement, false);
}
13、higher:返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null。
public E higher(E e) {
return m.higherKey(e);
}
14、isEmpty:如果此 set 不包含任何元素,则返回 true。
public boolean isEmpty() {
return m.isEmpty();
}
15、iterator:返回在此 set 中的元素上按升序进行迭代的迭代器。
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
16、last:返回此 set 中当前最后一个(最高)元素。
public E last() {
return m.lastKey();
}
17、lower:返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。
public E lower(E e) {
return m.lowerKey(e);
}
18、pollFirst:获取并移除第一个(最低)元素;如果此 set 为空,则返回 null。
public E pollFirst() {
Map.Entry<E,?> e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
19、pollLast:获取并移除最后一个(最高)元素;如果此 set 为空,则返回 null。
public E pollLast() {
Map.Entry<E,?> e = m.pollLastEntry();
return (e == null) ? null : e.getKey();
}
20、remove:将指定的元素从 set 中移除(如果该元素存在于此 set 中)。
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
21、size:返回 set 中的元素数(set 的容量)。
public int size() {
return m.size();
}
22、subSet:返回此 set 的部分视图
返回此 set 的部分视图,其元素范围从 fromElement 到 toElement。
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive) {
return new TreeSet<>(m.subMap(fromElement, fromInclusive,
toElement, toInclusive));
}
//返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
public SortedSet<E> subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false);
}
23、tailSet:返回此 set 的部分视图
返回此 set 的部分视图,其元素大于(或等于,如果 inclusive 为 true)fromElement。
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return new TreeSet<>(m.tailMap(fromElement, inclusive));
}
//返回此 set 的部分视图,其元素大于等于 fromElement。
public SortedSet<E> tailSet(E fromElement) {
return tailSet(fromElement, true);
}
*/
}
}