Java集合框架
Java集合框架
1、 什么是集合
-
概念:存放对象的容器。定义了对多个对象进行操作的常用方法。可实现数组的功能
-
集合和数组的区别:
(1)数组长度固定,集合长度不固定
(2)数组可以存储基本类型和引用类型,集合只能存储引用类型(对象)
(3)集合中存放的都是对象的引用,而非对象本身。所以我们称集合中的对象就是集合中对象的引用。对象本身还是存放在堆内存中
(3)数组存储的元素必须是同一个数据类型,集合存储的对象可以是不同数据类型的
-
存放的包:java.uti.*;
-
基本数数据类型和引用数据类型区别

-
类(class), 接口(interface),数组(array),(枚举类型、注解类型、字符串(String)类型) 。
简单来说,只要不是基本数据类型.都是引用数据类型。
2、 数组存储的特点:
一旦初始化以后,其长度就确定了。 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。
比如:String[] arr、int[] arr1、Object[] arr2
3、 数组存储的弊端:
- 一旦初始化以后,其长度就不可修改。
- 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
- 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
- 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
4、 集合存储的优点:
解决数组存储数据方面的弊端
5、 Collection体系集合

6、 Collection父接口
- 特点:代表一组任意类型的对象,无序、无下标、不能重复
- 常用的方法有:
| 方法 | 功能 |
|---|---|
| boolean add(Object obj) | 添加一个对象 |
| boolean addAll(Collection c) | 将一个集合中的所有对象添加到此集合中 |
| void clear() | 清空此集合中的所有对象 |
| boolean contains(Object o) | 检查此集合中是否包含o对象 |
| boolean equals(Object o) | 比较此集合是否与指定对象相等 |
| boolean isEmpty() | 判断此集合是否为空 |
| boolean remove(Object o) | 在此集合中移除o对象 |
| int size() | 返回此集合中的元素个数 |
| Object[ ] toArray() | 将此集合转换成数组 |
6.1 Collection接口的使用
(1)添加元素
(2)删除元素
(3)遍历元素
(4)判断
-
创建集合
Collection collection = new ArrayList();
(1)添加元素
collection.add("苹果");
collection.add("雪梨");
collection.add("榴莲");
System.out.println("元素个数:"+collection.size());//输出:元素个数:3
System.out.println(collection); //输出:[苹果, 雪梨, 榴莲]
(2)删除元素
collection.remove("榴莲");
//collection.clear(); //清空集合
System.out.println("元素个数:"+collection.size());
(3)遍历元素
①使用增强for (不能使用for循环)
for (Object obj: collection) {
System.out.println(obj);
}
②使用迭代器(迭代器专门用来遍历集合的一种方式)
Iterator的三个方法
- hasNext()
2. next()
3. remove()
Iterator it = collection.iterator();
while (it.hasNext()){
String s = (String) it.next(); //强转类型
System.out.println(s);
//collection.remove(s); 不能使用collection的remove()方法,会报并发修改异常
it.remove(); //可以使用it.remove(); 进行移除元素
}
System.out.println("元素个数:"+collection.size());//元素个数:0
注意:使用迭代器的过程中,不能使用collection中的方法
(4)判断
System.out.println(collection.contains("西瓜"));//判断是否包含元素 西瓜
System.out.println(collection.isEmpty()); //判断集合是否为空
7、 List集合
- 特点:有序、有下标、元素可以重复
- 常用的方法有:
| 方法 | 功能 |
|---|---|
| void add(int index, Object o) | 在index位置插入对象o |
| boolean addAll(int index, Collection c) | 将一个集合中的元素添加到此集合中的index位置 |
| Object get(int index) | 返回集合中指定位置的元素 |
| List subList(int fromIndex, int toIndex) | 返回fromIndex和toIndex之间的集合的元素 |
7.1 List子接口的使用
(1)添加元素 (会对基本类型进行自动装箱)
(2)删除元素
当删除数字与索引矛盾时 对数字强转
list.remove((Object) 10) 或 list.remove(new Integer(10))
(3)遍历元素
(4)判断
-
创建List集合(通过实现类创建)
List list = new ArrayList();
或者 List list = new LinkedList();
(1)添加元素
list.add("苹果");
list.add("华为");
list.add(0,"小米"); //在0位置添加
System.out.println("元素个数:"+list.size());//输出 元素个数:3
System.out.println(list.toString());//输出 [小米, 苹果, 华为]
(2)删除元素
list.remove("苹果");
System.out.println(list.toString()); //输出 [小米, 华为]
list.remove(0);//删除0号位置的元素
(3)遍历集合
①使用for i
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
②使用增强for
for (Object o : list) {
System.out.println(o);
}
③使用iterator迭代器
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
④使用列表迭代器 ListIterator (注意和迭代器的区别)
ListIterator lit = list.listIterator();
while (lit.hasNext()){
System.out.println(lit.nextIndex()+":"+lit.next());//从前往后遍历
}
while (lit.hasPrevious()){
System.out.println(lit.previousIndex()+":"+lit.previous());//从后往前遍历
}
(4)判断
list.contains() 和 list.isEmpty()
(5)获取某个元素所在位置 :list.indexOf()
(6)返回子集合(含头不含尾) :subList(int fromIndex, int toIndex)
7.2 List实现类
-
ArrayList【重点】:
- 数组结构实现,查询快、增删慢
- jdk1.2版本,运行效率快、线程不安全
-
Vector:
- 数组结构实现,查询快、增删慢
- jdk1.0版本,运行速度慢、线程安全
-
LinkedList:
- 双向链表结构实现,增删快、查询慢
1、 ArrayList
-
创建ArrayList集合
ArrayList arrayList = new ArrayList();
(1)添加元素 arrayList.add();
(2)删除元素 arrayList.remove(new Student("name", 10));
这里重写了 equals(this == obj) 方法
public boolean equals(Object obj){
//1 判断是不是同一个对象
if(this == obj){
return true;
}
//2 判断是否为空
if(obj == null){
return false;
}
//3 判断是否是Student类型
if(obj instanceof Student){
Student == (Student)obj;
//4 比较属性
if(this.name.equals(s.getName()) && this.age == s.getAge()){
return true;
}
}
//5 不满足条件返回false
return false;
}
(3)遍历元素【重点】
①使用for
②使用增强for
③使用迭代器
Iterator it = arrayList.iterator();
while(it.hasNext()){
Student s = (Student)it.next(); //强转
}
④使用列表迭代器
ListIterator li = arrayList.listIterator();
while(li.hasNext()){
Student s = (Student)li.next(); //从前往后遍历
}
while(li.hasPrevious()){
Student s = (Student)li.previous();//从后往前遍历
}
(4)判断
arrayList.contains(); 和 arrayList.isEmpty();
(5)查找某个元素的下标
arrayList.indexof();
ArrayList源码分析
DEFAULT_CAPACITY = 10; //默认容量是10
//注意:如果没有向集合中添加任何元素时,容量0,添加一个后,容量为10
//每次扩容是原来的1.5倍
elementData:存放元素的数组
size :实际元素个数
2、 Vector
-
创建Vector集合
Vector vector = new Vector();
增加、删除、判断同上的集合
遍历:使用枚举器遍历集合(Enumeration)
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String s = (String) en.nextElement();
System.out.println(s.toString());
}
3、LinkedList
-
创建链表集合:
LinkedList li = new LinkedList();
常用方法与List一致
4、ArrayList 和 LinkedList的区别
两者结构的实现方式

8、 Set集合
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
- 增、删、遍历、判断与collection一致
- 创建Set集合:通过实现类创建
- Set set = new HashSet();
- Set set = new TreeSet();
8.1 Set实现类
-
HashSet【重点】
- 基于HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
-
TreeSet
- 基于排列顺序实现元素不重复
- 实现了SortSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
1. HashSet
-
HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet
-
创建HashSet集合:
Set hashSet = new HashSet();
-
存储结构:哈希表(数组+链表+红黑树)
-
HashSet按Hash算法来存储集合中的元素,因此具有很好地存取和查找性能。
-
存储过程(重复依据):需重写hashCode和equals方法
- 根据hashCode计算保存的位置,如果位置为空,直接保存;若不为空,则进行第2步
- 再执行equals方法,如果equals为true,则认为是重复的,否则形成链表
-
特点:
- 基于HashCode计算元素的存放位置
- 通过重写HashCode的方法,可得知:
- 利用31这个质数,减少散列冲突
- 31提高执行效率 ,31 * i = (i << 5) - i 转为移位操作
- 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet中的存储位置
- 当存入元素的hashCode值相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
- 如果两个元素的equals()方法返回true,但它们的hashCode()返回值不相等,hashSet将会把它们存储在不同的位置,但依然可以添加成功
-
HashSet具有以下特点:
- 不能保证元素的排列顺序
- 不可重复
- HashSet不是线程安全的
- 集合元素可以是null
1.添加元素: hashSet.add( );
2.删除元素: hashSet.remove( );
3.遍历操作
-
增强for:
for( type typevar : hashSet)
-
迭代器:
Iterator it = hashSet.iterator( );`
4.判断: hashSet.contains( ); hashSet.isEmpty();
2. TreeSet
-
创建TreeSet集合:
TreeSet treeSet = new TreeSet();
-
存储结构:红黑树
-
要求:元素必须要实现Comparable接口,否则会报异常!!重写compareTo()方法,返回值为0,认为是重复元素
写一个TreeSet集合
/*
使用TreeSet保存数据,存储一个学生类
存储数据:红黑树
*/
public class Test {
public static void main(String[] args) {
//创建TreeSet集合
TreeSet<Student> treeSet = new TreeSet<>();
//添加元素
Student s1 = new Student("彭于晏",20);
Student s2 = new Student("胡歌",22);
Student s3 = new Student("杨洋",21);
treeSet.add(s1);
treeSet.add(s2);
treeSet.add(s3);
System.out.println("元素个数:"+treeSet.size());
System.out.println(treeSet.toString());
}
写到这里,运行后会发现异常,编译器会返回ClassCastException,名为类型转换异常:Student cannot be cast to java.lang.Comparable,这时的解决办法有两种:
第一种:Student类需实现Comparable接口,实现接口中的compareTo()方法
//Student类实现Comparable接口
public class Student implements Comparable<Student>{
String name;
int age;
@Override //实现接口中的compareTo()方法
public int compareTo(Student o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age - o.getAge();
return n1 == 0 ? n2 : n1;
}
这时再执行,就能正常存储Student元素到TreeSet中
第二种:不需实现Comparable接口,需在创建TreeSet集合时使用Comparator接口
Comparator :实现定制比较(比较器)
Comparable: 可比较的
public class Test2 {
public static void main(String[] args) {
//创建集合,并指定比较规则
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() { //创建一个匿名内部类实现接口
@Override
public int compare(Student o1, Student o2) {
int n1 = o1.getName().compareTo(o2.getName());
int n2 = o1.getAge()-o2.getAge();
return n1==0 ? n2:n1;
}
});
//添加元素
Student s1 = new Student("aaa",20);
Student s2 = new Student("zxh",21);
Student s3 = new Student("hello",23);
treeSet.add(s1);
treeSet.add(s2);
treeSet.add(s3);
System.out.println("元素个数:"+treeSet.size());
System.out.println(treeSet.toString());
除了以Map结尾的类之外,其他类都实现Collection接口,而以Map结尾的类实现了Map接口
9、 Map体系集合

10、 Map父接口
- 特点:存储一对数据(Key—Value),无序、无下标,键不可重复,值可重复
- 常用的方法有:
| 方法 | 功能 |
|---|---|
| V put(K key, V value) | 将对象存到集合中,关联键值。key重复则覆盖原值 |
| Object get(Object key) | 根据键获得对应的值 |
| Key |
返回所有的key |
| Collection |
返回包含所有值的Collection集合 |
| Set<Map.Entry<K, V>> | 键值匹配的Set集合 |
10.1 Map接口的使用
Map集合的特点:
(1)存储键值对
(2)键不能重复,值可以重复
(3)无序
-
创建Map集合 比如键值对都为String类型
Map<String, String> hashMap = new HashMap<>();
(1)添加元素
hashMap.put("cn","中国");
hashMap.put("usa","美国");
hashMap.put("uk","英国");
hashMap.put("cn","zhongguo"); //key重复,后面的值会覆盖原值
System.out.println("元素个数:"+hashMap.size()); //输出 元素个数:3
System.out.println(hashMap.toString()); //输出 {usa=美国, uk=英国, cn=zhongguo}
(2)删除
hashMap.remove("usa");
System.out.println("元素个数:"+hashMap.size());
(3)遍历【重点】
①使用keySet() :返回的是key
Set<String> keySet = hashMap.keySet(); //返回key的Set集合,可以用增强for或者迭代器遍历
for (String key : keySet) {
System.out.println(key+"---"+hashMap.get(key)); //get():返回键所对应的值
}
②使用entrySet() : 返回的是键值对
Set<Map.Entry<String, String>> entries = hashMap.entrySet(); //返回键值对的Set集合,可以用增强for或者迭代器遍历
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+"----"+entry.getValue());
}
(4)判断
System.out.println(hashMap.containsKey("cn"));
System.out.println(hashMap.containsValue("泰国"));
10.2 Map集合的实现类
-
HashMap:
- jdk1.2版本,线程不安全,运行效率快;允许用null作为key或者value
-
Hashtable:
1. HashMap【重点】
-
存储结构:哈希表(数组+链表+红黑树)
-
使用key可使hashcode和equals作为重复依据:需重写hashCode和equals方法
-
增、删、遍历、判断与Map集合一致
-
源码分析总结:
- HashMap刚创建时,table是null,节省空间,当添加第一个元素时,table容量调整为16
- 加载因子为0.75,当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
- jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
- jdk1.8 当链表长度 <6 时 调整成链表
- jdk1.8 以前,链表时头插入,之后为尾插入
2. TreeMap
-
存储结构:红黑树
-
TreeMap集合的使用:
- 添加元素时,写代码的流程时与TreeSet一致,都需要实现Comparable接口,实现接口中的compareTo()方法;或者不需实现Comparable接口,需在创建TreeSet集合时使用Comparator接口。区别是TreeMap能对key自动排序
- 删、遍历、判断与Map集合一致
知识点:
-
HashMap集合和HashSet集合添加元素时都需要重写hashCode和equals方法
-
TreeMap集合与TreeSet集合添加元素时一样都需要实现Comparable接口
11、 Collections工具类
- 概念:集合工具类,定义了除了存储以外的集合常用方法
- 常用方法:
| 方法 | 功能 |
|---|---|
| public static void reverse(List<?> list) | 反转集合元素中的顺序 |
| public static void shuffle(List<?> list) | 随机重置集合元素的顺序 |
| public static void sort(List |
升序排序(元素类型必须实现Comparable接口) |
| public static void copy(dest, src) | 将src的所有元素复制到另一个集合中 |
Collections工具类的使用
1.首先创建一个集合
ArrayList<Integer> list = new ArrayList<>();
list.add(12);
list.add(22);
list.add(5);
list.add(35);
list.add(17);
(1)排序sort() :默认升序
System.out.println("排序之前:"+list.toString());
Collections.sort(list);
System.out.println("排序之后:"+list.toString());
(2)二分查找 binarySearch():返回负数表示不存在
int i = Collections.binarySearch(list, 12);
System.out.println(i);
(3)复制 copy() :要求目标集合与原来的集合长度要一样
ArrayList<Integer> dest = new ArrayList<>();
for(int j = 0; j < list.size(); j++) {
dest.add(0);
}
Collections.copy(dest,list);
System.out.println(dest);
(4)反转 reverse()
Collections.reverse(list);
System.out.println("反转之后:"+list);
(5)打乱 shuffle() :每次执行顺序都不一样
Collections.shuffle(list);
System.out.println("打乱之后:"+list.toString());
2.补充两个转换
(1)集合转成数组: toArray()
Integer[] array = list.toArray(new Integer[0]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));
(2)数组转成集合 :asList()
String[] name = {"小明","小红","小东"};
//转成之后的集合是一个受限集合,不能添加和删除
List<String> strings = Arrays.asList(name);
System.out.println(strings.toString());
//把基本数据类型的数组转成集合时,需要修改为包装类型
Integer[] num = {10,20,30,40};
List<Integer> list1 = Arrays.asList(num);
System.out.println(list1.toString());
12、 泛型
- Java泛型是jdk1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数化传递
- 常见形式有:泛型类、泛型接口、泛型方法
- 语法:<T,...> T被称为类型占位符,表示一种引用类型
- 好处
- 提高代码的重用性
- 防止类型转换异常,提高代码的安全性
12.1 泛型类
写一个泛型类,语法:类名
/*
泛型类
语法:类名<T>
T是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开
*/
public class MyGeneric<T> {
//使用泛型T
//1.创建变量
T t;
//泛型作为方法的参数
public void show(T t){
System.out.println(t);
}
//泛型作为方法的返回值
public T getT(){
return t;
}
}
使用泛型类
public class TestGeneric {
public static void main(String[] args) {
//创建泛型类对象
//注意:1.泛型只能使用引用类型 2.不同泛型类型对象之间不能相互赋值
MyGeneric<String> generic = new MyGeneric<String>();
generic.t="hello";
generic.show("你好"); //输出 你好
String s = generic.getT();
System.out.println(s); //输出 hello
MyGeneric<Integer> generic1 = new MyGeneric<>();
generic1.t = 10;
generic1.show(100);//输出 100
Integer t = generic1.getT();
System.out.println(t); //输出 10
// MyGeneric<String> my = generic1; //报错 不同泛型类型对象之间不能相互赋值
}
}
12.2 泛型接口
写一个泛型接口,语法:接口名
/*
泛型接口
语法:接口名<T>
注意:不能使用泛型创建静态常量
*/
public interface MyInterface<T> {
String name = "张三";
T show(T t);
}
第一种实现类(在接口名直接标明泛型类型)
public class MyImplement implements MyInterface<String>{
@Override
public String show(String s) {
System.out.println(s);
return s;
}
}
第二种实现类(不知道哪一种泛型类型时,通过测试类创建对象时标明泛型类型)
public class MyImplement2<T> implements MyInterface<T>{
@Override
public T show(T t) {
System.out.println(t);
return t;
}
}
//测试类
public static void main(String[] args) {
MyImplement2<Integer> integerMyImplement2 = new MyImplement2<>();//标明使用的泛型类型
integerMyImplement2.show(100);
}
12.3 泛型方法
写一个泛型方法类,语法:修饰符 返回值类型 方法名()
/*
泛型方法
语法:修饰符 <T> 返回值类型 方法名(){ }
*/
public class GenericMethod {
public <T> T show(T t){
System.out.println("泛型类型:"+t);
return t;
}
}
使用泛型方法(泛型类型不需要传递,而是根据所写参数决定)
GenericMethod genericMethod = new GenericMethod();
genericMethod.show("中国加油");
genericMethod.show(100);
genericMethod.show(3.14);
13、 Java集合的总结
1.Java集合类存放于java.uti包中,是一个用来存放对象的容器
①集合只能存放对象。比如你存一个int型数据1放入集合中,其实它是自动转换成integer类后存入的,Java中每一种基本类型都有对应的引用类型
②集合存放的是多个对象的引用,对象本身还是放在堆内存中
③集合可以存放不同类型,不限数量的数据类型
2.Java集合可分为List、Set和Map三种大体系
-
Set:无序、无下标、不可重复的集合
-
List:有序、有下标、可重复的集合
-
Map:具有映射关系的集合,
3.在JDK5之后,增加了泛型,Java集合可以记住容器中对象的数据类型


浙公网安备 33010602011771号