文章目录
- Java基础之集合篇
-
- 一、Java集合概述及特点
- 二、Collection 接口的常用方法
- 三、ArrayList及List的常用方法
- 四、ArrayList、Vector、LinkedList
- 五、Set的主要实现类HashSet
- 六、LinkedHashSet的特点及实现
- 七、Set的实现类TreeSet
- 八、Map接口
- 九、Collections工具类的使用
- 1.Collections的特点:
- 2.排序操作:(均为static方法)
- 3.查找、替换
- 4.同步控制
- 5.Enumeration
- 十、ArrayList、LinkedList 和 HashMap 的底层原理分析
Java基础之集合篇
一、Java集合概述及特点
1.集合概述
2.Collection 接口继承树
2.1 Collection 接口描述
3.Map接口继承树
二、Collection 接口的常用方法
1、Java 集合概述
Java 集合可分为 Collection 和 Map 两种体系
① Collection 接口:
Set: 元素无序、不可重复的集合
List: 元素有序、可重复的集合
② Map 接口:具有映射关系“key-value对”的集合
数组与集合的比较:
①.存储对象可以考虑:a.数组 b.集合
②.数组存储对象的特点:Student[] stu = new Student[20];stu[0] = new Student();…
弊端:① 一旦创建,其长度不可变。②真实的数组存放的对象的个数是不可知。
③ 数组与集合的区别:
a.数组声明了它容纳的元素的类型,而集合不声明。
b.数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。
c.数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。
d.数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。
2.collection 接口常用方法的使用说明及使用实例
说明:因为它是Set和List的接口,所有先拿collection举例,先说明Set和List两个集合公共方法的使用
2.1 size,add,addAll,isEmpty,clear
① size():返回集合中元素的个数
② add(Object obj):向集合中添加一个元素
③ addAll(Collection coll):将形参 coll 中包含的所有元素到当前集合中
④ isEmpty():判断集合是否为空
⑤ clear():清空集合元素
打印的结果
2.2 contains,containsAll,retainAll,remove
⑥ contains(Object obj):判断集合中是否包含指定的obj元素。如果包含,返回true,反之返回false。判断的依据:根据元素所在的类的equals()方法进行判断
明确:如果存入集合中的元素是自定义的对象。要求:自定义类要重写equals()方法!!!
⑦ containsAll(Collection coll):判断当前集合中是否包含coll中所有的元素
⑧ retainAll(Collection coll):求当前集合与coll的共有的元素。返回给当前集合
⑨ remove(Object obj):删除集合中的obj元素。若删除成功,返回true。否则,返回false
打印的结果
2.3 removeAll,equals
⑩ removeAll(Collection coll):从当前集合中删除包含在coll中的元素
⑪ equals(Object obj):判断集合中的所有元素是否完全相同
2.4 hashCode,toArray
⑫ hashCode():
⑬ toArray():将集合转化为数组
2.5 iterator
⑭ iterator():返回一个Iterator接口实现类的对象
打印的结果:
3.再谈集合遍历的方法
3.1使用迭代器Iterator实现集合的遍历
3.1.1 正确的写法:
Iterator接口实现集合遍历的示意图
3.1.2 错误的写法:
上面代码运行之后就会报 java.util.NoSuchElementException 的错
3.2 使用增强for循环实现集合的遍历
3.3 面试题
@Test
public void testFor1(){
String[] str = new String[]{
"AA","BB","DD"};
for(int i = 0; i < str.length; i++){
str[i] = i + "";
}
for(int i = 0; i < str.length; i++){
System.out.print(str[i] + " ");//0 1 2
}
}
@Test
public void testFor2(){
String[] str = new String[]{
"AA","BB","DD"};
for(String s : str){
s = "MM";//此处的s是新定义的局部变量,其值的修改不会对str本身造成影响
System.out.print(s + " ");//MM MM MM
}
for(int i = 0; i < str.length; i++){
System.out.print(str[i] + " ");//AA BB DD
}
}
三、ArrayList及List的常用方法
1.1 List的特点:
元素有序、可重复的集合
1.2 ArrayList:List的主要实现类(List中相对于Collection,新增加的方法)
1.2.1 add,addAll,get,remove,set
① void add(int index,Object ele):在指定的索引位置index添加元素ele
② boolean addAll(int index,Collection eles):添加 eles 到指定的 index 下
③ Object get(int index):获取指定索引的元素
④ Object remove(int index):删除指定索引位置的元素
⑤ Object set(int index,Object ele):设置指定索引位置的元素为ele
List常用的方法:增(add(Object obj))删(remove) 改(set(int index,Object obj))查(get(int index))插(add(int index,Object ele))长度(size())
打印的结果:
1.2.2 indexOf,lastIndexOf,subList
⑥ int indexOf(Object obj):返回obj在集合中首次出现的位置。没有的话,返回-1
⑦ int lastIndexOf(Object obj):返回obj在集合中最后一次出现的位置。没有的话,返回-1
⑧ List subList(int fromIndex,int toIndex):返回从fromIndex到toIndex结束的左闭右开的一个子list集合
打印的结果:
四、ArrayList、Vector、LinkedList
1.三者的存储性能和特性
ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素要涉及数组元素移动等内存操作,所以索引数据块而插入数据慢,Vector它是古老的实现类,由于使用了 synchronized方法(线程安全),通常性能上较ArrayList 差,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.如果在集合中使用数据量比较大的数据,用vector有一定的优势。而LinkedList使用了双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录本项即可,所以插入数据较快。因此一般都用来插入和删除。LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList可以被当作堆栈和队列来使用。
2.三者区别(面试题)
共同点:
ArrayList、LinkedList、Vector都是List接口的实现类,存储的数据都是有序的,可重复的
区别
- ArrayList:作为 List 的主要实现类;线程不安全的,效率高;底层使用数组实现
(Collections中定义了synchronizedList(List list)将此ArrayList转化为线程安全的) - LinkedList:对于频繁的插入、删除操作,建议使用此类,因为效率高;底层使用双向链表实现
- Vector:List的古老实现类;线程安全的,效率低;底层使用数组实现
五、Set的主要实现类HashSet
1.Set的特点
存储的元素是无序的,不可重复的!
a.无序性:无序性!= 随机性。真正的无序性,指的是元素在底层存储的位置是无序的。
b.不可重复性:当向 Set 中添加进相同的元素的时候,后面的这个不能添加进去。
说明:要求添加进Set中的元素所在的类,一定要重写equals()和hashCode()方法。进而保证Set中元素的不可重复性!
注:Set中至多只能有一个空元素
2.HashSet部分源码:
3.Set中的元素时如何存储的呢?使用了哈希算法。
向Set中添加元素a,首先通过hashCode(),计算元素a的哈希值,此哈希值就决定了此元素在Set底层存储的位置,如果此存储的位置上没有元素,则此元素a添加成功。如果此存储的位置上有元素b,则调用元素a所在类的equals()方法,将元素b作为参数传递过去。如果返回值为true,则表示元素a和b相同,则元素a添加不成功。如果返回值为false,则认为元素a和元素b不相同,此时元素a可以添加成功的。元素a与元素b使用链表存储。(jdk7.0 : a指向b;jdk8.0:b指向a)
要求:hashCode()方法要与equals()方法一致
六、LinkedHashSet的特点及实现
1.LinkedHashSet的特点:
使用链表维护了一个添加进集合中的顺序。导致当我们遍历LinkedHashSet集合元素时,是按照添加进去的顺序遍历的!(存储元素的位置还是无序的)
在 HashSet 底层存储结构的基础上,额外提供了一对指针。能够记录此Node元素的上一个和下一个元素。(对于频繁的遍历,效率高)
2.LinkedHashSet存储和遍历的示意图:
七、Set的实现类TreeSet
1.TreeSet 的特点
1.向TreeSet中添加的元素必须是同一个类的。
2.可以按照添加进集合中的元素的指定的顺序遍历。像String,包装类等默认按照从小到大的顺序遍历
3.当向TreeSet中添加自定义对象时,该对象如果没有实现Comparable接口时,就会报ClassCastException
4.当向TreeSet中添加自定义类的对象时,有两种排序方法:① 自然排序 ② 定制排序
5.自然排序: 要求自定义类实现java.lang.Comparable接口并重写其compareTo(Object obj)的抽象方法,在此方法中,指明按照自定义类的哪个属性进行排序
6.向TreeSet中添加元素时,首先按照compareTo()进行比较,一旦返回0,虽然仅是两个对象的同一个属性值相同。但是程序会认为这两个对象是相同的,进而后一个对象就不能添加进来。
compareTo()与hashCode()以及equals()三者保持一致!
2.自然排序的实例
package com.bean;
import java.util.Objects;
public class Person implements Comparable{
private Integer id;
private String name;
private Integer age;
public Person() {
}
public Person