一、集合是什么?
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); } */ } }
部分内容参考别人的作品: https://www.cnblogs.com/chenssy/