Java集合框架
目录
Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。集合是对象的容器,实现了对对象常用的操作。
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
- 接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
- 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
- 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
1、集合与数组的区别
2、Collection接口
2.1、Collection接口方法
编写如下代码进行演示Collection的使用:
import java.beans.beancontext.BeanContextChild;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection接口的使用
* (1)添加元素
* (2)删除元素
* (3)遍历元素
* (4)判断
* @author 86187
*/
public class collection {
public static void main(String[] args) {
Collection collection = new ArrayList();//Collection是接口不能被直接实例化
// * (1)添加元素
collection.add("1");
collection.add("2");
collection.add("3");
collection.add("3");
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
// * (2)删除元素
collection.remove("3");//观察结果发现此方法只能删除一个3,可以查看ArrayList类源码验证
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
// * (3)遍历元素
//3.1使用for each语句
for (Object object:collection) {
System.out.println(object);
}
//3.2使用迭代器(迭代器专门用来遍历集合的一种方式)
Iterator iterator = collection.iterator();
while(iterator.hasNext()){
String s = (String) iterator.next();
System.out.println(s);
iterator.remove();//删除当前数据
}
System.out.println("元素个数:"+collection.size());
// * (4)判断
System.out.println(collection.contains("3"));
System.out.println(collection.isEmpty());
}
}
结果如下:
元素个数:4
[1, 2, 3, 3]
元素个数:3
[1, 2, 3]
1
2
3
1
2
3
元素个数:0
false
true
3、List接口
编写如下代码进行演示List的使用:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class list {
public static void main(String[] args) {
List list = new ArrayList();
//添加元素
list.add("苹果");
list.add("小米");
list.add("华为");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//删除元素
list.remove("苹果");
list.remove(1);
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//遍历
for (int i=0;i<list.size();i++){//for循环
System.out.println(list.get(i));
}
for (Object object:list) {//增强for
System.out.println(object);
}
Iterator iterator = list.iterator();//迭代器
while(iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator listIterator = list.listIterator();//列表迭代器
while(listIterator.hasNext()){//从前往后
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
while(listIterator.hasPrevious()){//从后往前
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//判断
System.out.println(list.contains("华为"));
System.out.println(list.isEmpty());
//获取位置
System.out.println(list.indexOf("华为"));
}
}
结果如下:
元素个数:3
[苹果, 小米, 华为]
元素个数:1
[小米]
小米
小米
小米
0:小米
0:小米
false
false
-1
3.1、ArrayList
- 默认容量大小10
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class arraylist {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
// 添加元素
Student s1 = new Student("刘德华",19);
Student s2 = new Student("郭富城",20);
Student s3 = new Student("梁朝伟",18);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数"+arrayList.size());
System.out.println(arrayList.toString());
// 删除元素
/*
arrayList.remove(s1);
arrayList.remove(1);
System.out.println("元素个数"+arrayList.size());
System.out.println(arrayList.toString());
*/
arrayList.remove(new Student("刘德华",19));//删除失败,因为是通过equals(this==obj)判断,可以在Student类中重写该方法使得成功删除
System.out.println("元素个数"+arrayList.size());
// 遍历元素
Iterator iterator = arrayList.iterator();//迭代器
while(iterator.hasNext()){
Student s = (Student) iterator.next();
System.out.println(s.toString());
}
ListIterator listIterator = arrayList.listIterator();//列表迭代器
while (listIterator.hasNext()){
Student s = (Student) listIterator.next();
System.out.println(s.toString());
}
// 判断
System.out.println(arrayList.contains(s1));
System.out.println(arrayList.contains(new Student("郭富城",20)));//也是通过equal方法判断
// 查找
System.out.println(arrayList.indexOf(s2));
}
}
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if(o==null){
return false;
}
if(o instanceof Student){
Student s = (Student) o;
if (s.getName().equals(this.name)&&s.getAge()==(this.age)){
return true;
}
else
return false;
}
return false;
}
}
元素个数3
[Student{name='刘德华', age=19}, Student{name='郭富城', age=20}, Student{name='梁朝伟', age=18}]
元素个数2
Student{name='郭富城', age=20}
Student{name='梁朝伟', age=18}
Student{name='郭富城', age=20}
Student{name='梁朝伟', age=18}
false
true
0
3.2、Vector
import java.util.Enumeration;
import java.util.Vector;
public class vector {
public static void main(String[] args) {
Vector vector = new Vector();
vector.add("草莓");
vector.add("西瓜");
vector.add("苹果");
System.out.println("元素个数:"+vector.size());
System.out.println(vector);
vector.remove("草莓");
//vector.clear();//全部删除
System.out.println("元素个数:"+vector.size());
Enumeration enumeration = vector.elements();//枚举器遍历
while (enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());
}
System.out.println(vector.isEmpty());
System.out.println(vector.contains("苹果"));
}
}
3.3、LinkedList
import java.util.LinkedList;
public class linkedlist {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
//添加
linkedList.add("火锅");
linkedList.add("烧烤");
linkedList.add("水煮");
Student s1 = new Student("刘德华",19);
Student s2 = new Student("郭富城",20);
Student s3 = new Student("梁朝伟",18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList.toString());
//删除
linkedList.remove("火锅");
System.out.println("元素个数:"+linkedList.size());
//遍历
for (Object ob:linkedList) {
System.out.println(ob);//因为没有需求,就没有进行类型转换
}
}
}
4、泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法。
- 语法
- <T|K|V,...> T|K|V称为类型占位符,表示一种引用类型,不能是基本类型。
- 好处
- (1)提高代码的重用性
- (2)防止类型转换异常,提高代码的安全性
4.1、泛型类
package com.liuxiang.generics;
public class Generic<T> {
T t;//创建泛型
//泛型作为方法的参数
public void show(T t){
System.out.println(t);
}
//泛型作为方法的返回值
public T getT(){
return t;
}
}
package com.liuxiang.generics;
public class TestGeneric {
public static void main(String[] args) {
Generic<String> generic = new Generic<String>();
generic.t = "刘翔";
generic.show("123");
System.out.println(generic.getT());
Generic<Integer> generic1 = new Generic<Integer>();
generic1.t = 1;
generic1.show(2);
System.out.println(generic1.getT());
}
}
123
刘翔
2
1
4.2、泛型接口
package com.liuxiang.generics;
public interface MyInterface<T> {
String name = "刘翔";
//不能泛型静态常量
T server(T t);
}
package com.liuxiang.generics;
public class MyInterfaceImpl implements MyInterface<String>{
public static void main(String[] args) {
System.out.println(MyInterface.name);
MyInterfaceImpl myInterface = new MyInterfaceImpl();
myInterface.server("jhgh");
}
@Override
public String server(String s) {
System.out.println(s);
return null;
}
}
刘翔
jhgh
4.3、泛型方法
package com.liuxiang.generics;
public class MyGenericMethod {
public static void main(String[] args) {
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("刘翔");
MyGenericMethod.show("刘翔");
}
public static <T> void show(T t){
System.out.println("泛型方法"+t);
}
}
泛型方法刘翔
泛型方法刘翔
4.4、泛型集合
package com.liuxiang.generics;
import com.liuxiang.list.Student;
import java.util.Iterator;
import java.util.LinkedList;
public class genericlist {
public static void main(String[] args) {
LinkedList<Student> linkedList = new LinkedList();
//添加
Student s1 = new Student("刘德华",19);
Student s2 = new Student("郭富城",20);
Student s3 = new Student("梁朝伟",18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList.toString());
//删除
linkedList.remove("火锅");
System.out.println("元素个数:"+linkedList.size());
//遍历
for (Student student:linkedList) {
System.out.println(student);
}
Iterator<Student> iterator = linkedList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
元素个数:3
[Student{name='刘德华', age=19}, Student{name='郭富城', age=20}, Student{name='梁朝伟', age=18}]
元素个数:3
Student{name='刘德华', age=19}
Student{name='郭富城', age=20}
Student{name='梁朝伟', age=18}
Student{name='刘德华', age=19}
Student{name='郭富城', age=20}
Student{name='梁朝伟', age=18}
5、Set接口
- 特点:无序、无下标、元素不可重复。
- 方法:全部继承自Collection中的方法。
package com.liuxiang.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class setDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
//添加
set.add("华为");
set.add("小米");
set.add("苹果");
System.out.println("元素个数:"+set.size());
System.out.println(set.toString());
//删除
set.remove("小米");
System.out.println("元素个数:"+set.size());
//遍历
for (String string:set) {
System.out.println(string);
}
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(set.contains("华为"));
}
}
5.1、HashSet
-
存储结构:哈希表(数组+链表+红黑树)
-
基于HashCode计算元素存放位置。
-
当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
package com.liuxiang.Set;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<String>();//第二个String可写可不写
//添加元素
hashSet.add("刘德华");
hashSet.add("林志玲");
hashSet.add("周润发");
hashSet.add("梁朝伟");
hashSet.add("刘德华");//重复元素添加失败
System.out.println("元素个数:"+hashSet.size());
System.out.println(hashSet);
//删除元素
hashSet.remove("梁朝伟");
System.out.println(hashSet);
//遍历元素
for (String str:hashSet) {//增强for
System.out.println(str);
}
Iterator iterator = hashSet.iterator();//迭代器
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(hashSet.contains("林志玲"));
System.out.println(hashSet.isEmpty());
}
}
元素个数:4
[林志玲, 梁朝伟, 周润发, 刘德华]
[林志玲, 周润发, 刘德华]
林志玲
周润发
刘德华
林志玲
周润发
刘德华
true
false
- 存储过程:根据Hashcode计算保存的位置,如果位置为空,则直接保存,如果不为空,再执行equals方法,如果equals方法为true,则认为重复,否则,形成链表。
package com.liuxiang.Set;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<Person> hashSet = new HashSet();
//添加元素
Person s1 = new Person("刘德华",18);
Person s2 = new Person("林志玲",19);
Person s3 = new Person("梁朝伟",20);
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(new Person("林志玲",19));//如果不重写hashCode与equals方法,则该重复元素也会添加成功
System.out.println("元素个数:"+hashSet.size());
System.out.println(hashSet);
//删除元素
hashSet.remove(new Person("梁朝伟",20));
System.out.println(hashSet);
//判断
System.out.println(hashSet.contains(new Person("刘德华",18)));
System.out.println(hashSet.isEmpty());
}
}
package com.liuxiang.Set;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object object) {
if(object==null){
return false;
}
if(object instanceof Person){
Person person = (Person) object;
if(person.getAge()==this.age&&person.getName().equals(this.name));{
return true;
}
}
return false;
}
@Override
public int hashCode() {
int hash1 = this.name.hashCode();
int hash2 = this.age;
return hash1+hash2;
}
}
元素个数:3
[Person{name='刘德华', age=18}, Person{name='梁朝伟', age=20}, Person{name='林志玲', age=19}]
[Person{name='刘德华', age=18}, Person{name='林志玲', age=19}]
true
false
5.2、TreeSet
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
package com.liuxiang.Set;
/**
* 要求:使用TreeSet集合实现字符串按照长度进行排序
* Comparator接口实现定制比较
* @author liuxiang
*/
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<String>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1 = o1.length()-o2.length();
int n2 = o1.compareTo(o2);
return n1==0?n2:n1;
}
});
treeSet.add("123");
treeSet.add("12");
treeSet.add("1234");
System.out.println("元素个数:"+treeSet.size());
System.out.println(treeSet);
}
}
元素个数:3
[12, 123, 1234]
6、Map接口
Map用于保存具有映射关系的数据,Map里保存着两组数据:key和value,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map接口特点:(1)存储键值对 (2)键不能重复 (3)无序
* @author 86187
*/
public class MapDemo {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
System.out.println("元素个数:"+map.size());
System.out.println(map.toString());
//删除元素
map.remove("uk");
System.out.println(map.toString());
//遍历
Set<String> keySet = map.keySet();//使用keySet();
for (String str:keySet) {
System.out.println(str+"--------"+map.get(str));
}
Set<Map.Entry<String,String>> entrySet = map.entrySet();//使用entrySet();
for (Map.Entry<String,String> entry:entrySet) {
System.out.println(entry.getKey()+"-------"+entry.getValue());
}
//判断
System.out.println(map.containsKey("usa"));
System.out.println(map.containsValue("加拿大"));
}
}
元素个数:3
{usa=美国, uk=英国, cn=中国}
{usa=美国, cn=中国}
usa--------美国
cn--------中国
usa-------美国
cn-------中国
true
false
6.1、HashMap
- HashMap 刚创建时,table 是 null,为了节省空间,当添加第一个元素时,table 容量调整为16
- 当元素个数大于阈值(16*(加载因子0.75)=12)时,会进行扩容,扩容后大小为原来的2倍,目的是减少调整元素个数
- jdk1.8 当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树(左边节点比右边节点小),目的提高执行效率
- jdk1.8 当链表长度小于6时,调整成链表
- jdk1.8 以前,链表是头插入,jdk1.8以后是尾插入
package com.liuxiang.Map;
/**
* HashMap存储结构:哈希表(数组+链表+红黑树)
* 使用key可用hashCode与equals作为重复
* @author liuxiang
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Student,String> hashMap = new HashMap();
//添加元素
Student s1 = new Student("孙悟空",1001);
Student s2 = new Student("沙僧",1002);
Student s3 = new Student("猪八戒",1003);
hashMap.put(s1,"北京");
hashMap.put(s2,"南昌");
hashMap.put(s3,"上海");
hashMap.put(new Student("孙悟空",1001),"北京");//如果不重写hashCode与equals方法,则能够添加
System.out.println("元素个数"+hashMap.size());
System.out.println(hashMap.toString());
//遍历
System.out.println("---------------使用keySet()---------------");
Set<Student> keySet = hashMap.keySet();
for (Student key:keySet) {
System.out.println(key+":"+hashMap.get(key));
}
Iterator iterator = keySet.iterator();
while (iterator.hasNext()){
Student str = (Student) iterator.next();//此处将iterator.next()保存下来,好输出value
System.out.println(str+":"+hashMap.get(str));
}
System.out.println("---------------使用entrySet()------------------");
Set<Map.Entry<Student,String>> entrySet = hashMap.entrySet();
for (Map.Entry<Student,String> entry:entrySet) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
元素个数3
{Student{name='孙悟空', stuNum=1001}=北京, Student{name='沙僧', stuNum=1002}=南昌, Student{name='猪八戒', stuNum=1003}=上海}
---------------使用keySet()---------------
Student{name='孙悟空', stuNum=1001}:北京
Student{name='沙僧', stuNum=1002}:南昌
Student{name='猪八戒', stuNum=1003}:上海
Student{name='孙悟空', stuNum=1001}:北京
Student{name='沙僧', stuNum=1002}:南昌
Student{name='猪八戒', stuNum=1003}:上海
---------------使用entrySet()------------------
Student{name='孙悟空', stuNum=1001}:北京
Student{name='沙僧', stuNum=1002}:南昌
Student{name='猪八戒', stuNum=1003}:上海
6.2、Hashtable
- 默认初始容量11,加载因子0.75
- 子类Properties,要求ker和value都是String,通常用于配置文件的读取。
6.3、TreeMap
- 实现了SortedMap接口(是Map的子接口),可以对key自动排序。\
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 用compareTo()来判断重复元素。
package com.liuxiang.Map;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Student,String> treeMap = new TreeMap<Student,String>();
Student student1 = new Student("liuxiang",101);
Student student2 = new Student("yaoming",102);
Student student3 = new Student("sunyang",103);
treeMap.put(student1,"中国");
treeMap.put(student2,"中国");
treeMap.put(student3,"中国");
treeMap.put(new Student("sunyang",103),"中国人");
//TreeSet是用compareTo()来判断重复元素的,根据compareTo学号一样无法添加,但值却能覆盖value值
System.out.println("元素个数:"+treeMap.size());
System.out.println(treeMap.toString());//按照学号从小打大输出
System.out.println("------------keySet()-----------------");
for (Student str:treeMap.keySet()) {
System.out.println(str+":"+treeMap.get(str));
}
System.out.println("------------keySet()-----------------");
for (Map.Entry<Student,String> entry:treeMap.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
元素个数:3
{Student{name='liuxiang', stuNum=101}=中国, Student{name='yaoming', stuNum=102}=中国, Student{name='sunyang', stuNum=103}=中国人}
------------keySet()-----------------
Student{name='liuxiang', stuNum=101}:中国
Student{name='yaoming', stuNum=102}:中国
Student{name='sunyang', stuNum=103}:中国人
------------keySet()-----------------
Student{name='liuxiang', stuNum=101}:中国
Student{name='yaoming', stuNum=102}:中国
Student{name='sunyang', stuNum=103}:中国人
7、Collections工具类
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CollectionsDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList();
list.add(12);
list.add(20);
list.add(13);
list.add(56);
list.add(34);
list.add(17);
list.add(16);
System.out.println("排序之前:"+list);
Collections.sort(list);//排序
System.out.println("排序之后:"+list);
int i = Collections.binarySearch(list,13);//二分查找,需排序后使用
System.out.println(i);
List<Integer> dest = new ArrayList<>();//复制,要求目的集合与原集合大小一样
for (int j=0;j<list.size();j++){
dest.add(0);
}
Collections.copy(dest,list);
System.out.println("复制集合:"+dest);
Collections.reverse(list);//反转reverse
System.out.println("反转之后:"+list);
Collections.shuffle(list);//打乱shuffle
System.out.println("打乱之后"+list);
//补充:list转成数组
Integer[] integers = list.toArray(new Integer[0]);
System.out.println(integers.length);
System.out.println(Arrays.toString(integers));
//数组转成一个受限集合(不能添加和删除)
String[] strings = {"张三","李四","王五"};
List<String> list1 = Arrays.asList(strings);
//list1.add("赵六");会报错
System.out.println(list1);
//基本类型数组转集合,需要修改为包装类型
int[] ints = {111,222,333};
List<int []> list2 = Arrays.asList(ints);
Integer[] integers1 = {111,222,333};
System.out.println(list2);
List<Integer> list3 = Arrays.asList(integers1);
System.out.println(list3);
}
}
排序之前:[12, 20, 13, 56, 34, 17, 16]
排序之后:[12, 13, 16, 17, 20, 34, 56]
1
复制集合:[12, 13, 16, 17, 20, 34, 56]
反转之后:[56, 34, 20, 17, 16, 13, 12]
打乱之后[17, 56, 12, 34, 13, 16, 20]
7
[17, 56, 12, 34, 13, 16, 20]
[张三, 李四, 王五]
[[I@4554617c]
[111, 222, 333]