java基础-集合

java基础-集合

七月 02, 2020

Java基础-集合

java集合框架图

如上图可以看出java集合可以分为Collection和Map两大接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
* @see     Set
* @see List
* @see Map
* @see SortedSet
* @see SortedMap
* @see HashSet
* @see TreeSet
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Collections
* @see Arrays
* @see AbstractCollection
* @since 1.2
1
public interface Collection<E> extends Iterable<E> {
1
public interface Map<K,V> {

常用的实现类有 ArrayListLinkedListHashSet以及HashMap

  1. ArrayList

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    private static final long serialVersionUID = 8683452581122892189L;

    /**
    * Default initial capacity.
    */
    private static final int DEFAULT_CAPACITY = 10;

ArrayList的初始容量为10;但是它的容量可以动态增长;当添加元素达到容量上限时会自动扩容会原始容量的1.5倍

1
2
List arrayList = new ArrayList();无参构造实例化;初始容量值10;
List arrayList1 = new ArrayList(100);初始容量为100;

如上也可以手动初始化容量

常用方法:

方法 描述
boolean add(E e) 将元素插入到集合的末尾
void add(int Index, E element) 将元素插入到指定索引位置,原先索引位置后面的元素依次向后移动
void clear( ) 清空集合中所有元素
boolean contains(Object o) 判断集合中是否包含此指定元素,一般用于去除重复元素(Set无重复!!!)
boolean remove(Object o) 删除指定元素
E remove(int index) 删除指定索引位置的元素
E set(int index, E element) 将元素替换到指定索引位置,和add方法有区别
E get(int index); 获取指定索引位置的元素,比较常用
boolean isEmpty( ) 判断集合是否为空
int size(); 获取集合中元素个数
Object[ ] toArray( ) 获取集合中所有元素组成的对象数组
List subList(int fromIndex, int toIndex) 获取集合中起止位置元素所组成的子列表(不包含末尾位置)

由于ArrayList的抽象父类(AbstractCollection)重写了toString方法,因此可以直接以集合名的方式直观的获取集合中的所有元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";

StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}

可以直观的看出使用了迭代器的方式

2.Iterator

方法 描述
boolean hasNext() 如果仍有元素可以迭代,则返回 true
E next() 返回迭代的下一个元素
void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素

迭代器的remover方法还有很大考究门道,过段时间再细究

2020-07-08更新

先贴一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
List<String> list = new ArrayList<>();
list.add("烬");
list.add("李青");
list.add("劫");
list.add("盖伦");
System.out.println("list-----"+list);
Iterator<String> iterator = list.iterator();
List<String> list1 = new ArrayList<>();
while (iterator.hasNext()){
System.out.println("iterator.next()---"+iterator.next());
iterator.remove();
list1.add(iterator.next());
}
System.out.println("list1-------"+list1);
System.out.println("-----------------------------------");
System.out.println(list);

运行结果:

1
2
3
4
5
6
list-----[烬, 李青, 劫, 盖伦]
iterator.next()---烬
iterator.next()---劫
list1-------[李青, 盖伦]
-----------------------------------
[李青, 盖伦]

每次调用next()方法,都会得到一个值,那么这个迭代的过程就会相应向后走一步(打个可能不是很恰当的比喻,数一一个队伍,数了一个之后,相应的会向后面移动一步。。。)上面的这段代码可以看成是首先用next();数了 最前面的”烬”, 打印的结果便是 “烬” , 然后调用remove();把这个 “烬” 移除队伍,那么此时队伍就变成了[李青, 劫, 盖伦],接着判断是否还可以数,—->( [李青, 劫, 盖伦] 可以继续数—->)执行,接着数了”李青”并把它放到另一个队伍中去(向后走一步),再判断是否还可以数,—>( [李青, 劫, 盖伦] 可以继续数—->) 执行,此时注意”李青”已经数过了,下一个数的就是”劫”,打印的结果也是劫,接着remove();把这个 “劫” 移除队伍; 这时队伍变成了[李青, 盖伦]再最后数了“盖伦”并同时也将其放到另一个队伍中去,综上队伍已经全部数完(方法不再执行);那么最后原先的队伍就从[烬, 李青, 劫, 盖伦]变成了[李青, 盖伦],相应的另一个队伍里也是[李青, 盖伦]。。。

此处用这个放到另一个队伍的比喻不是很恰当,但目的是为了表明这个next();执行的效果—>迭代的过程会相应向后走一步

千人千面,每个人的理解都各不相同,但是最后的明白的都是同一个道理(多搞两把代码打上断点走一遍)

1
next();和remove();是相互依存的,调用remove();之前必须先调用next();否则会抛出java.lang.IllegalStateException

3.LinkedList

ArrayList 类常用方法与 List 接口基本相同,LinkedList 类则比 List 接口多了一些方便操作 头元素和尾元素的方法

常用方法如下:

方法 描述
void addFirst(E e) 把新元素插入到列表中的最前位置
void addLast(E e) 与上与之相反
E getFirst( ) 获取列表中最前位置的元素
E getLast( ) 与上与之相反
E peek( ) 获取列表中最前位置的元素,但此元素仍保留在列表中
E peekFirst( ) 获取列表中最前位置的元素,但此元素仍保留在列表中 E
E peekLast( 与上与之相反
E poll( ) 获取列表中最前位置的元素,同时把此元素从列表中删除
E pollFirst( ) 获取列表中最前位置的元素,同时把此元素从列表中删除
E pollLast( 获取列表中最后位置的元素,同时把此元素从列表中删除
void push(E e) 把指定元素压入到栈顶
E pop( ) 从栈中弹出栈顶元素

ArrayList 的内部实现是基于内部数组 Object[],类似于可变长的数组。LinkedList 的内部 实现是基于一组连接的记录,类似于一个链表结构。 在 ArrayList 的前面或中间插入数据时,必须将其后的所有数据相应的后移,花费较多时间,所以,当程序添加元素主要是在后面,并且需要随机地访问其中的元素时,优先使用 ArrayList 会得到比较好的性能;

访问 LinkedList 中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素地 去查找,直到找到所需的元素为止,但在添加元素到原有元素中间时效率很高,所以,当程序需要经常在指定位置添加元素,并且按照顺序访问其中的元素时,优先使用 LinkedList(随机访问的效率比较低)

4.HashSet

HashSet 类是将元素存储在散列表中,适合用于不需要有序的元素序列,并能实现快速查 找特定元素。如果想要提高 HashSet 的性能,可以指定 HashSet 中元素的个数;如果大约知道 HashSet 中最终会插入多少元素,可以把元素个数设置为其值的 1.5 倍;如果元素过多,将导 致 HashSet 检索性能下降

HashSet();方法的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;

private transient HashMap<E,Object> map;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
......

以上只是无参构造方法HashSet();其后还有一些有参构造方法,无一例外都是通过 new HashMap()的方式得到的

HashSet的常用方法有如下:

方法 描述
boolean add(E e) 如果指定的元素尚不存在,则将其添加到该集合中
boolean contains(Object o) 如果此集合包含指定的元素,则返回 true,否则返回 false
boolean isEmpty() 如果此集合不包含任何元素,则返回 true,否则返回 false
Iterator iterator() 返回此集合中元素的迭代器
boolean remove(Object o) 从该集合中删除指定的元素
int size() 返回此集合中的元素数量

就常用方法而言,Set 接口与 Collection 接口基本一致

HashSet类里并无获取元素的方法,只能通过Set里面的Iterator 获取

所有的Collection都实现了 Iterator 接口