JAVA集合
-
集合概念:对象的容器,定义了对多个对象进行操作的常用方法,可实现数组的功能
-
和数组的区别
-
数组长度固定,集合长度不固定
-
数组可以存储基本类型和引用类型,集合只能存储引用类型 (装箱和拆箱操作)
-
-
位置:java.util.*;
Collection体系集合
interface Collection:该体系结构的根接口,代表一组对象,成为集合
List接口特点:有序,有下标,元素可重复
Set接口特点:无序,无下标,元素不可重复
Collection父接口
-
特点:代表一组任意类型的对象,无序,无下标,不可重复
-
方法:
-
boolean add(Object obj) //添加一个对象。
-
boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
-
void clear()//清空此集合中的所有对象。
-
boolean contains (Object o) //检查此集合中是否包含o对象。
-
boolean equals(0bject o) //比较此集合是否与指定对象相等。
-
boolean isEmpty() //判断此集合是否为空。
-
boolean remove (0bject o) //在此集合中移除o对象。
-
int size() //返 回此集合中的元素个数。
-
0bject[] toArray() //将 此集合转换成数组。
-
Iterator<E> iterator() 返回在此 collection 的元素上进行迭代的迭代器。 (遍历集合的方法)
Collection 接口的使用:
//1. 添加元素
collection.add("苹果");
collection.add("香蕉");
collection.add("西瓜");
collection.add("榴莲");
System.out.println("元素个数:" + collection.size());
System.out.println(collection);
//2. 删除元素
//collection.remove("榴莲");
//collection.clear();
//System.out.println("元素个数:" + collection.size());
//3. 遍历元素【重点】
//3.1 增强for循环(不可以使用for循环,因为集合无下标)
System.out.println("===========3.1 增强for循环==============");
for (Object object:collection) {
System.out.println(object);
}
//3.2 使用迭代器(迭代器专门用来遍历集合的一种方式)
//hasNext();有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
System.out.println("===========3.2 使用迭代器==============");
Iterator it = collection.iterator();
while (it.hasNext()){
String next = (String) it.next();
System.out.println(next);
//ConcurrentModificationException:并发修改异常
//不允许使用其他的方法改变集合元素
//collection.remove(next);
//但是可以使用迭代器自身的remove()方法
//it.remove();
}
System.out.println("元素个数:"+ collection.size());
//4. 判断
System.out.println(collection.isEmpty());
System.out.println(collection.contains("西瓜"));
List子接口
特点:有序,有下标,元素可重复
方法:
-
void add(int index0bject o) //在index位 置插入对象o
-
boolean addAll(int index, Collection c) //将一个集合中的元素添加到此集合中的index位置。
-
0bject get(int index) //返 回集合中指定位置的元素。
-
List subList(int fromIndex, int toIndex) //返 回fromIndex和toIndex之间的集合元素。
-
ListIterator<E> listIterator() 返回此列表元素的列表迭代器(按适当顺序)。
-
ListIterator<E> listIterator(int index) 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
List 接口的使用
//创建列表
List list = new ArrayList();
//1 添加
list.add("iPhone");
list.add("realme");
list.add(0,"moto");
list.add("xiaomi");
list.add(2,"iqoo");
System.out.println("元素个数:" + list.size());
System.out.println(list.toString());
//2 删除
//list.remove("realme");
//list.remove(0);
// list.clear();
//System.out.println("删除之后元素个数:"+list.size());
//3 遍历
//3.1 for循环遍历
System.out.println("===========for循环遍历============");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//3.2 增强for循环遍历
System.out.println("===========增强for循环遍历============");
for (Object object:list) {
System.out.println(object);
}
//3.3 迭代器遍历
System.out.println("===========Iterator迭代器遍历============");
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//3.4 列表迭代器遍历,和Iterator区别:ListIterator可以向前或向后遍历,添加 删除 修改元素
System.out.println("===========列表迭代器遍历 从前往后============");
ListIterator lit = list.listIterator();
while (lit.hasNext()){
System.out.println(lit.next());
}
System.out.println("===========列表迭代器遍历 从后往前============");
while (lit.hasPrevious()){
System.out.println(lit.previousIndex() + ":" + lit.previous());
}
//4 判断
System.out.println(list.isEmpty());
System.out.println(list.contains("华为"));
//5 获取位置
System.out.println(list.indexOf("realme"));
List实现类
-
ArrayList[重点]:
-
数组结构实现,查询快、增删慢;
-
JDK1.2版本,运行效率快、线程不安全。
-
ArrayList类add()方法源码分析:
默认容量:DEFAULT_CAPACITY = 10
注意:如果没有向集合中添加任何元素,容量为0; 添加任意一个元素之后,容量为10;每次扩容大小为原来的1.5倍
存放元素的数组:Object[] elementData
实际元素个数:size
添加方法:add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
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);
}
-
Vector:
-
数组结构实现,查询快、增删慢;
-
JDK1.0版本,运行效率慢、线程安全。
-
-
LinkedList:
-
链表结构实现,增删快,查询慢。
-
LinkedList类add()方法源码分析:
int size; 集合大小
Node first; 链表的头节点
Node last; 链表的尾节点
Node 节点
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
ArrayList和LinkedList的区别
不同结构的实现方式
ArrayList:必须开辟连续空间,查询快,增删慢。 LinkedList:无需开辟连续空间,查询慢,增删快。
泛型
-
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
-
常见形式有泛型类、泛型接口、泛型方法。
-
语法:
-
<T,…> T称为类型占位符,表示一种引用类型。
-
-
好处:
-
(1)提高代码的重用性
-
(2)防止类型转换异常,提高代码的安全性
-
泛型集合
-
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
-
特点:
-
编译时即可检查,而非运行时抛出异常。
-
访问时,不必类型转换(拆箱)
-
不同泛型之间引用不能相互赋值,泛型不存在多态。
-
Set子接口
特点:无序,无下标,元素不可重复
方法:全部继承自Collection中的方法。
Set实现类
HashSet[重点] :
-
基于HashCode实现元素不重复。
-
当存入元素的哈希码相同时,会调用equals进行确认, 如结果为true,则拒绝后者存入。
-
存储结构:哈希表(数组+链表+红黑树【JDK1.8之后】)
-
存储过程:
-
(1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步
-
(2)再执行equals方法,如果equals方法为true,则认为是重复,否则形成链表
-
equals()方法与hashcode()方法重写
@Override
public int hashCode() {
int n1 = this.name.hashCode();
int n2 = this.age;
return n1+n2;
}
@Override
public boolean equals(Object obj) {
//判断是否同一个对象
if (this == obj){
return true;
}
//判断对象是否为空
if (obj == null){
return false;
}
//判断对象是否属于Person
if (obj instanceof Person) {
Person s = (Person) obj;
//判断属性是否相等
if (this.name.equals(s.getName()) && this.age == s.getAge()){
return true;
}
}
//不满足条件返回false
return false;
}
TreeSet:
-
基于排列顺序实现元素不重复。
-
实现了SortedSet接口, 对集合元素自动排序。
-
元素对象的类型必须实现Comparable接口,指定排序规则。
-
通过CompareTo方法确定是否为重复元素。
-
存储结构:红黑树
ClassCastException解决方法:CompareTo方法重写
//先按姓名比,再按年龄比
@Override
public int compareTo(Person o) {
int n1 = this.name.compareTo(o.getName());
int n2 = this.age - o.getAge();
return n1 == 0 ? n2 : n1;
}
Comparator:实现定制比较(比较器)
TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge() - o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1 == 0 ? n2 : n1;
}
});
Map体系集合
interface Map的特点:
-
用于存储任意键值对(Key-Value)
-
键:无序、无下标、不允许重复(唯一)
-
值:无序、无下标、允许重复
Map父接口
-
特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复。
-
方法:
-
V put(K key,V value) //将对象存入到集合中,关联键值。key重复则覆盖原值。
-
0bject get (0bject key) //根据键获取对应的值。
-
Set<K> keySet() //返回此映射中包含的键的 Set 视图。
-
Collection<V> values() //返回包含所有值的Collection集合。
-
Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。
-
//3 遍历
//3.1 使用keySet();
System.out.println("--------keySet()----------");
//Set<String> keySet = map.keySet();
for (String key: map.keySet()) {
System.out.println(key +"------"+ map.get(key));
}
//3.2 使用entrySet();
System.out.println("--------entrySet()----------");
//Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry: map.entrySet()) {
System.out.println(entry.getKey() +"------"+ entry.getValue());
}
Map集合的实现类
HashMap[重点]:
JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value。
-
基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。
-
HashMap() 构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
-
方法:同Map接口
-
存储结构:哈希表(数组+链表+红黑树)
-
使用key的hashcode()和equals()作为重写:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNo == student.stuNo && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNo);
}
HashMap源码分析
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16//hashMap初始容量大小
static final int MAXIMUM_CAPACITY = 1 << 30;//hashMap的数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子
static final int TREEIFY_THRESHOLD = 8;//jdk1.8 当链表长度大于8时,调整成红黑树
static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8 当链表长度小于6时,调整成链表
static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8 当链表长度大于8时,并且集合元素大于等于64时,调整成红黑树
transient Node<K,V>[] table;//哈希表中数组
transient int size;//元素个数
无参构造
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
put方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
源码分析总结:
-
HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16
-
当元素个数大于阈值(16*0.75=12)时, 会进行扩容,扩容后大小为原来的2倍。目的是减少调整元素的个数。
-
jdk1.8 当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树,目的提高执行效率
-
jdk1.8 当链表长度小于6时,调整成链表
-
jdk1.8 以前,链表时头插入,jdk1.8以后时是尾插入
Hashtable:
JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
构造方法:Hashtable() 用默认的初始容量 (11) 和加载因子 (0.75) 构造一个新的空哈希表。
Properties:
Hashtable的子类,要求key和value都是String。 通常用于配置文件的读取。
Properties类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
TreeMap :
实现了SortedMap接口(是Map的子接口),可以对key自动排序。
* ClassCastException
* implements Comparable<Student> compareTo(Student o)
* @author mamba
@Override
public int compareTo(Student o) {
int n1 = this.stuNo-o.getStuNo();
return n1;
}
TreeMap<Student, String> students = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n1 = o1.getStuNo() - o2.getStuNo();
return n1;
}
});
Collections工具类
-
概念:集合工具类,定义了除了存取以外的集合常用方法。
此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
-
方法:
-
public static void reverse(List<?> list) //反转集合中元素的顺序
-
public static void shuffle(List<?> list) //随机重置集合元素的顺序
-
public static void sort(List<T> list) //升序排序(元素类型必须实现Comparable接口)
-
static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
//使用二分搜索法搜索指定列表,以获得指定对象。
-
static <T> void copy(List<? super T> dest, List<? extends T> src)
//将所有元素从一个列表复制到另一个列表。
-