1.集合的概念
1.1 什么是集合
概念:对象的容器,实现了对对象的常用操作。可实现数组的功能。
和数组区别:
(1)数组长度固定,集合长度不固定;
(2)数组可存储基本类型和引用类型,而集合只能存储引用类型;
2.Collection接口
2.1 collection体系结构
2.2 Collection父接口
1.特点:代表一组任意类型的对象,无序、无下标、不能重复。
2.迭代方法(Iterator):
(1)hasNext() : 有没有下一个元素;
(2)next() : 获取下一个元素;
(3)remove() : 删除当前元素;
public static void main(String[] args) {
Collection collection =new ArrayList();
collection.add("小王");
collection.add("小刘");
collection.add("小张");
//(1)使用增强for循环遍历
for(Object object : collection){
System.out.println(object);
}
//(2)使用迭代器的方式(遍历集合的专属方法)
Iterator it = collection.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
注意:迭代过程当中不允许使用collection的其他方法改变集合的元素(并发修改异常)。
Iterator it = collection.iterator(); while(it.hasNext()){ System.out.println(it.next()); collection.remove(it.next()); }但是如果仍要删除,可以使用 it.remove(),本质上删除的是上一个遍历过的元素;
(4)判断:collection.contains();
collection.isEmpty();
3.List接口与实现类
1. 特点:有序、有下标、元素可重复,必须开辟连续空间。
2. 遍历迭代:
(1) 列表迭代器(List专属):ListIterator;
(2)可以正序遍历,也可逆序遍历,相较于Iterator可遍历角标。
public static void main(String[] args) {
List list =new ArrayList();
list.add("小明");
list.add("小红");
list.add("小蓝");
//使用for遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//使用增强for
for (Object object: list) {
System.out.println(object);
}
//使用迭代器
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//使用列表迭代器
ListIterator lit = list.listIterator();
//正序迭代
while(lit.hasNext()){
System.out.println(lit.nextIndex() + ":" + lit.next());
}
//逆序迭代
while(lit.hasPrevious()){
System.out.println(lit.previousIndex() + ":" + lit.previous());
}
}
3.集合中不能存储基本数据类型,因此存数字时会自动装箱,在删除某个数字的时候,调用remove方法直接删除该数字,需要将该数字进行装箱后删除。如 list.remove(new Integer(20)),当然利用角标也可以删除。
list.subList(1,3),返回子集合,含头不含尾;
3.1 ArrayList[重点]
1. 存储结构:数组结构实现
2. 特点:查询块、增删慢,运行效率快、线程不安全;
3. 功能:和List一致;
4. 源码分析:
(1)默认容量大小为 10;
注意:如果没有向集合中添加任何元素时,容量为 0,添加一个元素后,容量为10,超过之后会自动扩容。每次扩容都是原来的1.5倍,比如到达11的时候,此时容量为15。
(2)elementData 用来存放元素的数组;
(3)size为实际元素个数
3.2 Vector
1. 数组结构实现,查询快、增删慢;
2. jdk1.0版本,运行效率慢、线程安全;
public static void main(String[] args) {
Vector vector=new Vector();
vector.add("苹果");
vector.add("香蕉");
vector.add("梨子");
System.out.println("元素个数:" + vector.size());
//2.遍历,使用枚举器
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String o = (String) en.nextElement();
System.out.println(o);
}
//3.判断
System.out.println(vector.contains("苹果"));
System.out.println(vector.isEmpty());
}
3.3 LinkedList(链表结合)
(1) 链表结构实现,增删快、查询慢;
(2)存储结构:双向链表,无需开辟连续空间;
4. 泛型和工具类
1. Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
2. 常见的形式有泛型类、泛型接口、泛型方法。
3. 语法:<T,....> , T称为类型占位符,表示一种引用类型,如果编写多个,用逗号隔开。
4. 好处:
(1)提高代码的重用性
(2)防止类型转换异常,提高代码的安全性。
注意:泛型只能使用引用类型,不同泛型类型之间不能相互赋值。
5. 泛型接口的两种使用方式:
第一种:在使用接口时就确定好泛型的类型;
public class MyInterfaceImpl implements MyInterface<String>{
}
第二种:使用时不确定泛型的类型,但是用的是泛型类实现接口。
public class MyInterfaceImpl<T> implements MyInterface<T>{
}
6. 泛型方法:
(1)语法:<T> 返回值类型
(2)使用:
//定义
public class MyGenericMethod {
//泛型方法
public <T> void show1(T t){
System.out.println("泛型方法" + t);
}
public <T> T show2(T t){
System.out.println("泛型方法" + t);
return t;
}
}
//使用
public class Test2 {
public static void main(String[] args) {
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show1("字符串");
myGenericMethod.show1(200);
}
}
7. 泛型方法在使用的时候无需指定参数的类型,传什么值就会自动匹配到值的类型。此方法类似于方法重载,在相同的参数条件下,一个泛型方法可代替多个重载方法,提高了代码的重用性。
8. 泛型集合:
(1)概念:参数化类型、类型安全的集合、强制集合元素的类型必须一致。
(2)特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
5.Set接口与实现类
5.1 HashSet(重点)
1. 基于HashCode实现元素不重复;
2. 当存入元素的哈希码相同时,会调用equal进行确认,如果结果为true,则拒绝后者存入。
3. 存储结构:数组+链表+jdk1.8后有红黑树
4. 存储过程:
(1)根据hashCode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步。
(2)再执行equals方法,如果equals方法为true,则认为重复,否则,形成链表。
5. 特点:
- 基于HashCode计算元素存放位置
- 利用31这个质数,减少散列冲突
- 31提高执行效率
31 * i = (i << 5) - i
转为移位操作
- 31提高执行效率
- 当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
- 利用31这个质数,减少散列冲突
- 新建集合
HashSet<String> hashSet = new HashSet<String>();
- 添加元素
hashSet.add( );
- 删除元素
hashSet.remove( );
6. 遍历操作
(1)增强for for( type type : hashSet)
(2)迭代器 Iterator<String> it = hashSet.iterator( );
7. 判断 hashSet.contains( );
hashSet.isEmpty();
5.2 TreeSet:
- 基于排列顺序实现元素不重复。
- 实现了sortedSet接口,对集合元素自动排序。
- 元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过CompareTo方法确定是否为重复元素。
1. 存储结构:红黑树(左边节点比右边节点小)
创建集合 TreeSet<String> treeSet = new TreeSet<>()
添加元素 treeSet.add();
删除元素 treeSet.remove();
遍历 1. 增强for 2. 迭代器
判断 treeSet.contains();
2. 补充:TreeSet集合的使用
Comparator 实现定制比较(比较器)
Comparable 可比较的(自己实现的比较规则)
// 重写compare
@override
public int compare(Person o1, Person o2){
int n1 = o1.getAge()-o2.getAge();
int n2 = o1.getName().comareTo(o2.getName());
return n1 == 0 ? n2 : n1;
}
6.Map接口与实现类
1. 特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复。
2. 方法:
V put(K key,V value) :将对象存入到集合中,关联键值。key重复则覆盖原值。
Object get(Object key) :根据键获取对应的值;
Set<K> :返回所有的 key;
Collection<V> values():返回包含所有值的Collection集合。
Set<Map.Entery<K,V>> :键值匹配的Set集合。
3. 遍历:有两种方法,一种是遍历keySet,一种是遍历map.entrySet(),map.entrySet()的遍历效率比keySet高,因为keySet只能遍历key,而获取值时需要调用map.get(key)方法,相当于再次遍历一次。
4. 方法案例:
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//1.添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
System.out.println(map.size());
System.out.println(map.toString());
//2.删除
map.remove("usa");
System.out.println(map.toString());
//3.遍历
// Set<String> keyset = map.keySet();
for (String key: map.keySet()) {
System.out.println(key + " : " + map.get(key));
}
System.out.println("--------------entry--------------");
//3.2使用entrySet方法(键值对)
// Set<Map.Entry<String,String>> entries = map.entrySet();
for (Map.Entry<String,String> entry : map.entrySet()){
System.out.println(entry.getKey()+ " : "+ entry.getValue());
}
}
5.1 HashMap(重点):
- 存储结构:哈希表(数组+链表+红黑树);
- 使用key可使hashcode和equals作为重复;
- JDK1.2版本,线程不安全,运行效率快;允许用null作为key或者value;
- 增、删、遍历、判断与上述一致;
原码分析总结:
- HashMap刚创建时,table是null,节省空间,当添加第一个元素时,table容量调整为16
- 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
- jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
- jdk1.8 当链表长度 <6 时 调整成链表
- jdk1.8 以前,链表时头插入,之后为尾插入
HashSet和HashMap之间的关系:
在HashSet源码中,可以发现HashSet方法调用了HashMap,add方法中也用的是map.put()方法。总而言之,HashSet实质上调用了hashMap实现,拥有相同的结构。
Hashtable:
线程安全,运行效率慢;不允许null作为key或是value;
Properties:
hashtable的子类,要求key和value都是string,通常用于配置文件的读取;
TreeMap:
存储结构:红黑树,因此存储对象需要实现Comparable接口;
实现了SortedMap接口(是map的子接口),可以对key自动排序;
5.2 Collections
1. 概念:集合工具类,定义了除了存取以外的集合常用方法
2. 直接二分查找int i = Collections.binarySearch(list, x);
成功返回索引
3. 其他方法 : copy复制、reverse反转、shuffle打乱
// list转成数组
Integer[] arr = list.toArray(new Integer[10]);
sout(arr.length);
sout(Array.toString(arr));
// 数组转成集合
// 此时为受限集合,不能 添加和删除!
String[] name = {"张三","李四","王五"};
List<String> list2 = Arrays.asList(names);
// 把基本类型数组转为集合时,需要修改为包装类
Integer[] nums = {100, 200, 300, 400, 500};
List<Integer> list3 = Arrays.asList(nums);