Java集合基础知识(List,Set)

2 篇文章 0 订阅

目录

1.数组和集合

2.Collection的常用方法

3.List集合

3.1.ArrayList

3.1.1.jdk1.7

3.1.1.jdk1.8

3.2.Vector(已废弃)

3.3.LinkedList

4.Set集合

4.1.HashSet

4.2.LinkedHashSet

4.3.TreeSet

4.3.1.内部比较器

4.3.2.外部比较器

5.Map集合

5.1.HashMap

5.1.1.了解Hashtable,LinkedHashMap,TreeMap


1.数组和集合

数组

数组和集合都是对多个数据进行内存存储操作,不是持久化存储,简称容器。

数组的特点

  • 一旦指定长度,就不可以更改
  • 申明了同一类型数据就只能存放该类型的数据

数组的缺点

  1. 数组长度确定了就不可更改
  2. 删除,增加元素,都效率低下
  3. 数组中实际元素的数量没有提供对应的方法或者属性来获取
  4. 数组存储:有序,可重复,对无序,不可重复的数组不能满足要求

针对上诉缺点,就引入了新的存储数据结构-----集合

不同的集合数据结构不一样,集合不一样,特点也不一样

集合

集合分两类

  1. 一个数据一个数据的存储(Collection)
  2. 一对一对的存储(Map)

2.Collection的常用方法

增加:boolean add(E e);boolean addAll(Collection<? extends E> c)

删除:void clear();boolean remove(Object o)

查看:Iterator<E> iterator();int size()

判断:boolean contains(Object o);boolean equals(Object o);boolean isEmpty()

循环方式只有两种:

  1. 增强for循环
  2. iterator迭代器
Collection<Object> collection = new ArrayList<>();
collection.add("1");

//增强for循环
for(Object obj : collection){
    System.out.println(obj);
}
//迭代器
Iterator<Object> iterator = collection.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

3.List集合

不唯一,有序

常用的实现类有ArrayList,Vector,LinkedList

常用方法

增加:add(int index,E element);

删除:remove(Object o);remove(int index)

修改:set(int index,E element)

查看:get(int index)

遍历方式:

  1. 普通for循环
  2. 增强for循环
  3. iterator迭代器

扩展的方法都与index相关

3.1.ArrayList

底层跟stringbuilder类似,两个重要的属性:

Object[] elementData;//Object类型的数组,默认长度10
int size;//当前数组已经使用的大小,默认0

3.1.1.jdk1.7

在初始化时候,直接初始化数组elementData,默认数组长度是10

public ArrayList(){
    this(10);
}

ArrayList在Add()方法中,

  1. 触发条件:原来的数组都满了之后才扩容
  2. 扩容原有长度的1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);
  3. 将老数组中的内容复制到新的数组中,然后返回新数组

例如:原来的数组长度是10,扩容后新的数组长度是15。

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);
}

3.1.1.jdk1.8

在初始化时候,直接初始化数组elementData,默认数组长度是0

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

ArrayList在Add()方法中,底层才创建默认长度为10的数组,比jdk1.7节省了内存,剩下的都跟jdk1.7一样

ArrayList在jdk1.7和1.8的比较

默认构造器

  • 1.7默认初始化长度是10的数组
  • 1.8默认初始化长度是0的数组

add()方法

  • 1.7数组满了之后开始数组扩容
  • 1.8默认初始化长度是10的数组,如果数组满了就开始数组扩容

3.2.Vector(已废弃)

跟ArrayList高度类似,两个重要属性:

Object[] elementData;
int elementCount;

默认构造器,elementData数组长度10

public Vector() {
    this(10);
}

所有方法都加了线程安全的关键字synchronized

数组扩容是原有长度的2倍:int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

private void grow(int minCapacity) {
	// overflow-conscious code
	int 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);
}

区别和优缺点

底层都是数组的扩容

与ArrayList的区别

  • ArrayList底层扩容长度是数组的1.5倍,线程不安全,但效率高
  • Vector底层扩容长度是数组的2倍,线程安全,但效率低,所有被淘汰使用

都具备数组的优缺点

  • 查询效率高
  • 删除,增加元素,效率低
迭代器, Iterable接口,iterator()方法,Iterator接口 ,三者的区别?

ArrayList类中的内部类Iter实现了Iterator接口,有三个重要的方法:

  • boolean hasNext()     //是否是最有一个元素
  • E next()     //获取当前游标cursor的数组元素
  • remove()    //删除当前游标cursor的数组元素

ArrayList类中的内部类ListItr实现了ListIterator接口,是Iter的增强版,可以解决并发修改异常(ConcurrentModificationException)。

List<Integer> lists = new ArrayList<>();
ListIterator<Integer> listIter = lists.listIterator();
while(listIter.hasNext()){
	Integer i = listIter.next();
	if(i == 3){
		listIter.add(2);
	}
}

3.3.LinkedList

常用方法

增加:addFirst(E e);addLast(E e);

            offer(E e);offerFirst(E e);offerLast(E e)

删除:poll();

           pollFirst();pollLast();

           removeFirst();removeLast();//1.6新提出的方法,不抛异常,增强了健壮性

查看:element()

           getFirst();getLast();

           indexOf(Object o);LastIndexOf(Object o)

           peek();

           peekFirst();peekLast();

底层原理

逻辑结构下

ArrayList:线性表(数组);LinkedList:线性表(双向链表

双向链表中每一个节点包含:

  • 前一个元素的地址;
  • 当前元素值;
  • 后一个元素的地址

jdk1.7和jdk1.8源码都一样,证明如下:

transient int size = 0;//链表的使用大小
transient Node<E> first;//上一个节点对象
transient Node<E> last;//下一个节点对象

//内部类
private static class Node<E> {
	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;
	}
}

4.Set集合

唯一,无序

常用的实现类:HashSet,LinkedHashSet,TreeSet等

4.1.HashSet

底层:哈希表(HashMap或者数组+链表)

除了系统提供的引入数据类型(Integer,String等)之外,自定义引入数据类型(User,Dog等)一定要重写equals和hashCode方法,才能保证无序和唯一。

两个关键属性

private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();

原理(以Integer为例)

底层是HashMap,HashMap的底层是哈希表(数组+链表),具体看HashMap的底层原理

public HashSet() {
    map = new HashMap<>();
}

在添加数据的时候,

  1. 调用对应的hashCode方法计算哈希值
  2. 通过哈希值和一个表达式计算在数组中的存放位置
  3. 如果发生哈希碰撞,需要key的hashcode,equals比较和==比较

4.2.LinkedHashSet

特点:唯一,有序(按照元素的存放顺序)

底层:哈希表

继承了HashSet,在HashSet的基础上多了一个总的链表,这个链表将放入的元素串在一起,方便有序的遍历

4.3.TreeSet

特点:唯一,有序(默认按照升序,二叉树的中序遍历)

底层:二叉树(TreeMap)

二叉树的遍历

  • 先序遍历:根 左 右 
  • 中序遍历:左 根 右 ==>当前TreeSet的遍历方式
  • 后序遍历:左 右 根

如何做到的有序呢?

利用了接口中的内部比较器或者外部比较器

4.3.1.内部比较器

implements Comparable<>

@Override
public int compareTo(Test o){}

例如:Integer实现了内部比较器

implements Comparable<Integer>

public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}

例如:String实现了内部比较器

implements Comparable<String>

public int compareTo(String anotherString) {
	int len1 = value.length;
	int len2 = anotherString.value.length;
	int lim = Math.min(len1, len2);
	char v1[] = value;
	char v2[] = anotherString.value;

	int k = 0;
	while (k < lim) {
		char c1 = v1[k];
		char c2 = v2[k];
		if (c1 != c2) {
			return c1 - c2;
		}
		k++;
	}
	return len1 - len2;
}

自定义类,也需要实现内部比较器,重写compareTo()方法

4.3.2.外部比较器

implements Comparator<>

@Override
public int compare(Test o1, Test o2) {
	return 0;
}

使用方式如下:

Comparator comparator = new Comparator<String>() {
	@Override
	public int compare(String o1, String o2) {
		return 0;
	}
};
TreeSet<String> treeSet = new TreeSet<String>(comparator);

//或者jdk8写法:
TreeSet<String> treeSet = new TreeSet<String>((o1, o2) -> {
    return 0;
});

5.Map集合

特点:Key,Value键值对方式存储,Key不允许重复,Value可以重复

常用的实现类:HashMap,HashTable,TreeMap

常用方法

增加:put(K key,V value)

删除:clear();remove(Object key)

查看:entrySet();get(Object key);keySet();size();value();

判断:containsKey(Object key);containsValue(Object value);

           equals(Object o);isEmpty();

5.1.HashMap

特点:key唯一,无序

底层:哈希表(数组+链表)

哈希表原理:数据对应的类型,必须重写hashCode方法和equals方法

5.1.1.了解Hashtable,LinkedHashMap,TreeMap

Hashtable(已废弃)与HashMap,与ArrayList和Vector类似

HashMap:JDK1.2,效率高,线程不安全,key可以存入null值,并且key的null值也是遵循唯一的特点

Hashtable:JDK1.0,效率低(方法都加入了Synchronized关键字),线程安全,key不可以存入null值

LinkedHashMap继承了HashMap,与LinkedHashSet类似

特点:唯一,有序(按照输入顺序进行排序)

底层:哈希表

TreeMap,与TreeSet类似

特点:唯一,有序(按照升序或者降序)

原理:二叉树,key遵循二叉树的特点,放入集合的key对应的数据类型一定要实现比较器(内部比较器,外部比较器二选一)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彼岸花@开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值