java 集合笔记
代码
文章中用到的代码,我都放在了gitee仓库里:
https://gitee.com/lai_di_hao/java-collection-exercise.git
概念
对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
和数组的区别
1、数组长度固定,集合长度不固定
2、数组可以存储基本类型和引用类型,集合只能存储引用类型
位置
java.util.*
Collection体系集合
Collection用法
package com.test3;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest {
public static void main(String[] args) {
Collection collection = new ArrayList();
//添加元素
collection.add("a");
collection.add("b");
collection.add("c");
System.out.println("元素个数:"+collection.size()); //元素个数:3
System.out.println(collection);//[a, b, c]
//删除元素
collection.remove("a");
System.out.println(collection);//[b, c]
//清空元素
collection.clear();
//遍历元素 (自带forEach+lamda表达式)
collection.forEach(e -> System.out.println(e));//b,c
//迭代器
//hasNext();有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
Iterator it = collection.iterator();
while (it.hasNext()){
String object = (String) it.next();
System.out.println(object);//b,c
it.remove();//删除当前元素,迭代过程中不能用Collection 的删除方法
}
//判断
System.out.println(collection.contains("b"));//true
System.out.println(collection.isEmpty());//false
}
}
List用法
package com.test3;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ListTest {
public static void main(String[] args) {
List list = new ArrayList<>();
//添加元素
list.add("a");
list.add("b");
list.add(0,"c");
System.out.println(list);//[c, a, b]
//删除元素
// list.remove("a");
// System.out.println(list);//[c, b]
list.remove(1);
System.out.println(list);//[c, b]
//遍历
//自带的forEach
list.forEach(e -> System.out.println(e));//b,c
//正常for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));//b,c
}
//迭代器
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());//b,c
}
//列表迭代器
//允许从前往后,和从后往前
ListIterator listIterator = list.listIterator();
//从前往后
while (listIterator.hasNext()){
//0:c
//1:b
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
//从后往前
while (listIterator.hasPrevious()){
//1:b
//0:c
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//判断
//与Collection 相同
}
//添加数据类型(自动装箱)
list.add(10);
list.add(20);
list.add(30);
list.add(40);
System.out.println(list);//[10, 20, 30, 40]
//删除元素
// list.remove(0);//[20, 30, 40]
list.remove(new Integer(10));
System.out.println(list);//[20, 30, 40]
//subList,返回子集合
System.out.println(list.subList(0, 2));//[20, 30],左包含右不包含
}
List实现类
ArrayList :
1、数组结构实现,查询快、增删慢
2、JDK1.2版本,运行效率快、线程不安全
Vector :
1、数组结构实现,查询快、增删慢
2、JDK1.0版本,运行效率慢、线程安全
LinkedList :
链表结构实现,增删快,查询慢
ArrayList
Students类:
package com.test3;
import java.util.Objects;
public class Students {
private String name;
private int age;
public Students(){
}
@Override
public String toString() {
return "Students{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Students(String name, int age) {
super();
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 boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
// Students students = (Students) o;
// return age == students.age && Objects.equals(name, students.name);
//重写
//判断是不是同一个对象
if (this == o){
return true;
}
//判断是否空
if (o == null){
return false;
}
//判断是否是Students类型
if (o instanceof Students){
Students students = (Students) o;
//比较属性
if (this.name.equals(students.getName())&&this.age == students.age){
return true;
}
}
//不满足
return false;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
ArrayListTest 类:
package com.test3;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList<>();
//添加元素
Students s1 = new Students("刘德华",20);
Students s2 = new Students("黎明",22);
Students s3 = new Students("张学友",18);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
//删除元素
arrayList.remove(new Students("刘德华",20));
//重写equals方法之前:3,没有删除成功
//重写equals方法之后:2,删除成功
System.out.println(arrayList.size());
//遍历元素
//迭代器
Iterator it = arrayList.iterator();
while (it.hasNext()){
Students s = (Students) it.next();
System.out.println(s.toString());
}
//列表迭代器(从前往后)
ListIterator lit = arrayList.listIterator();
while (lit.hasNext()){
Students s = (Students) lit.next();
System.out.println(s.toString());
}
//列表迭代器(从后往前)
//如果是直接逆序,这里就为false,但如果是先正序遍历,再进行逆序,这里就为true
System.out.println(lit.hasPrevious());
while (lit.hasPrevious()){
Students ss = (Students) lit.previous();
System.out.println(ss.toString());
}
//判断
System.out.println(arrayList.contains(new Students("张学友",18)));//true
System.out.println(arrayList.isEmpty());//false
//查找
System.out.println(arrayList.indexOf(s1));//-1
System.out.println(arrayList.indexOf(s2));//0
}
}
Vector
package com.test3;
import java.util.Enumeration;
import java.util.Vector;
public class VectorTest {
public static void main(String[] args) {
Vector vector = new Vector();
//添加元素
vector.add("a");
vector.add("b");
vector.add("c");
System.out.println(vector);//[a, b, c]
//删除元素
vector.remove(0);
System.out.println(vector);//[b, c]
vector.remove("b");
System.out.println(vector);//[c]
//遍历
//使用枚举器
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String o = (String) en.nextElement();
System.out.println(o);
}
//判断
System.out.println(vector.contains("c"));//true
System.out.println(vector.isEmpty());//false
}
}
LinkedList
package com.test3;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList list = new LinkedList();
//添加元素
Students s1 = new Students("刘德华",20);
Students s2 = new Students("黎明",22);
Students s3 = new Students("张学友",18);
list.add(s1);
list.add(s2);
list.add(s3);
System.out.println(list);//[Students{name='刘德华', age=20}, Students{name='黎明', age=22}, Students{name='张学友', age=18}]
//删除
list.remove(s1);//因为重写了equals所以删除成功
System.out.println(list);//[Students{name='黎明', age=22}, Students{name='张学友', age=18}]
//遍历
//普通for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//foreach
list.forEach(e -> System.out.println(e));
//迭代器遍历
Iterator it = list.iterator();
while (it.hasNext()){
Students s = (Students) it.next();
System.out.println(s.toString());
}
//列表迭代器(有逆序,写法一样)
ListIterator lit = list.listIterator();
while (lit.hasNext()){
Students s = (Students) lit.next();
System.out.println(s.toString());
}
//判断
System.out.println(list.contains(s2));//true
System.out.println(list.isEmpty());//false
//获取
System.out.println(list.indexOf(s2));//0
}
}
ArrayList 和 LinkedList 的区别
ArrayList :必须开辟连续空间,查询快,增删慢
LinkedList:无需开辟连续空间,查询慢,增删快
泛型
JDK1.5引入的新特性,本质是参数化类型,把类型当作参数传递
好处:
1、代码复用
2、防止类型转换异常,提高代码安全性
泛型类
package com.test3;
/**
* 泛型类
* 语法:类名<T>
* T是类型占位符,表示一种引用类型,如果多个就用逗号隔开
*/
public class GenericTest<T> {
public static void main(String[] args) {
//使用泛型类型创建对象
//注意:1泛型只能是引用类型,2不同泛型类型对象之间不能相互赋值
MyGeneric<String> myGeneric = new MyGeneric<>();
myGeneric.t = "hello";
myGeneric.show("test");//test
String s = myGeneric.getT();
System.out.println(s);//hello
MyGeneric<Integer> myGeneric1 = new MyGeneric<>();
myGeneric1.t = 100;
myGeneric1.show(200);//200
Integer integer = myGeneric1.getT();
System.out.println(integer);//100
}
}
class MyGeneric<T> {
//使用泛型T
//创建变量
T t;
//泛型作为方法的参数
public void show(T t){
System.out.println(t);
}
public T getT(){
return t;
}
}
泛型接口
package com.test3;
/**
* 泛型接口
* 语法:接口名<T>
*/
public class MyInterface<T> {
public static void main(String[] args) {
InterfaceImpl impl = new InterfaceImpl();
impl.server("asdsfs");//asdsfs
InterfaceImpl1 impl1 = new InterfaceImpl1();
impl1.server(1243213);//1243213
}
}
interface InterfaceTest<T> {
T server(T t);
}
//指定泛型
class InterfaceImpl implements InterfaceTest<String> {
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
//不指定泛型
class InterfaceImpl1<T> implements InterfaceTest<T> {
@Override
public T server(T t) {
System.out.println(t);
return null;
}
}
泛型方法
package com.test3;
/**
* 泛型方法
* 语法:<T>返回值类型
*/
public class GenericMethod {
public static void main(String[] args) {
TestMethod testMethod = new TestMethod();
testMethod.show("阿巴阿巴");//泛型方法:阿巴阿巴
testMethod.show(100000);//泛型方法:100000
}
}
class TestMethod {
//泛型方法
public <T> T show(T t){
System.out.println("泛型方法:"+t);
return t;
}
}
泛型集合
概念:参数化接口、类型安全的集合,强制集合元素类型必须一致
特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
用法:
package com.test3;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericList {
public static void main(String[] args) {
//这里泛型定义了用String类型,就只能添加String类型的数据
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("李白");
arrayList.add("吕布");
// arrayList.add(21312);//会报错
arrayList.forEach(e -> System.out.println(e));
ArrayList<Students> arrayList1 = new ArrayList<>();
Students s1 = new Students("刘德华",20);
Students s2 = new Students("黎明",22);
Students s3 = new Students("张学友",18);
arrayList1.add(s1);
arrayList1.add(s2);
arrayList1.add(s3);
Iterator<Students> it = arrayList1.iterator();
while (it.hasNext()){
Students s = it.next();
System.out.println(s.toString());
}
}
}
Set 集合
概述
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自 Collection 中的方法
Set 接口
package com.test3;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Set接口的使用
*/
public class SetTest {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
//添加数据
set.add("小米");
set.add("华为");
set.add("小米");
set.add("苹果");
set.add("oppo");
System.out.println(set);//[苹果, oppo, 华为, 小米] 重复的不会添加,且无序
//删除
set.remove("小米");
System.out.println(set);//[苹果, oppo, 华为]
//遍历
//foreach
set.forEach(e -> System.out.println(e));
//迭代器
Iterator<String> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//判断
System.out.println(set.contains("oppo"));//true
System.out.println(set.isEmpty());//false
}
}
Set 实现类
HashSet 使用
- 基于 HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者加入
存储过程:
- 根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空则执行第二步。
- 再执行equals方法为true,则认为是重复,否则,形成列表
用法:
package com.test3;
import java.util.HashSet;
import java.util.Iterator;
/**
* HashSet集合的使用
* 存储机构:哈希表
*/
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
//添加元素
hashSet.add("王林");
hashSet.add("苏铭");
hashSet.add("孟浩");
hashSet.add("白小纯");
// hashSet.add("王林");//重复的会添加失败
System.out.println(hashSet);//[孟浩, 王林, 白小纯, 苏铭]
//删除
hashSet.remove("孟浩");
System.out.println(hashSet);//[王林, 白小纯, 苏铭]
//遍历
//foreach
hashSet.forEach(e -> System.out.println(e));
//迭代器
Iterator<String> it = hashSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//判断
System.out.println(hashSet.contains("苏铭"));//true
System.out.println(hashSet.isEmpty());//false
HashSet<Students> hashSet1 = new HashSet<>();
Students s1 = new Students("刘德华",20);
Students s2 = new Students("黎明",22);
Students s3 = new Students("张学友",18);
hashSet1.add(s1);
hashSet1.add(s2);
hashSet1.add(s3);
hashSet1.add(s1);
System.out.println(hashSet1.size());//3
hashSet1.remove(new Students("张学友",18));
System.out.println(hashSet1.size());//2,因为重写过equals
//遍历,判断和上面一样
}
}
TreeSet 使用
概述:
- 基于排列顺序实现元素不重复。
- 实现了SortedSet 接口,对集合元素自动排序。
- 元素对象的类型必须实现 Comparable 接口,指定排序规则。
- 通过 CompareTo 方法确定是否为重复元素。
package com.test3;
import java.util.Iterator;
import java.util.TreeSet;
/**
* TreeSet的使用
* 存储结构:红黑树
*/
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<>();
//添加元素
treeSet.add("z");
treeSet.add("x");
treeSet.add("c");
treeSet.add("c");//重复元素不会添加
System.out.println(treeSet);//[c, x, z],会排序输出
//删除
treeSet.remove("x");
System.out.println(treeSet);//[c, z]
//遍历
//foreach
treeSet.forEach(e -> System.out.println(e));
//迭代器
Iterator<String> it = treeSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
Comparator 接口
package com.test3;
import java.util.Comparator;
import java.util.TreeSet;
/**
* TreeSet集合的使用
* Comparator:实现定制比较(比较器)
* Comparable:可比较的
*/
public class ComparatorTest {
public static void main(String[] args) {
TreeSet<Students> students = new TreeSet<>(new Comparator<Students>() {
@Override
public int compare(Students o1, Students o2) {
int n1 = o1.getAge()- o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());//比较两者名字,或是别的参数
return n1 == 0?n2:n1;
}
});
Students s1 = new Students("刘德华",20);
Students s2 = new Students("黎明",20);
Students s3 = new Students("张学友",18);
students.add(s1);
students.add(s2);
students.add(s3);
//[Students{name='张学友', age=18}, Students{name='刘德华', age=20}, Students{name='黎明', age=20}]
//先按年龄,再按姓名顺序输出
System.out.println(students);
}
}
Map 体系集合
Map 接口
特点:
- 用于存储任意键值对(Key-Value)
- 键:无序、无下标、不允许重复(唯一,重复则覆盖)
- 值:无序、无下标、允许重复
使用:
package com.test3;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map接口的使用
*
*/
public class MapTest {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//添加元素
map.put("cn","中国");
map.put("usa","美国");
map.put("uk","英国");
map.put("uk","asdsa");
System.out.println(map);//{usa=美国, uk=asdsa, cn=中国},无序,且键重复覆盖
//删除
// map.remove("usa");
// System.out.println(map);//{uk=asdsa, cn=中国}
//遍历
//使用KeySet()
Set<String> keyset = map.keySet();//获取所有健
for (String key : keyset){
System.out.println(key+"---"+map.get(key));
}
// 使用entrySet(),效率高于KeySet()
Set<Map.Entry<String,String>> entries = map.entrySet();//获取所有键值对
for (Map.Entry<String,String> entry : entries){
System.out.println(entry.getKey()+"---"+entry.getValue());
}
//判断
System.out.println(map.containsKey("cn"));//true
System.out.println(map.containsValue("印度"));//false
System.out.println(map.isEmpty());//false
}
}
Map 集合实现类
- HashMap:JDK1.2版本,线程不安全,运行效率快,允许用null 作为key或者value
- Hashtable:JDK1.0版本,线程安全,运行效率慢,不允许null 作为key或者value
- Properties:Hashtable 的子类,要求key 和 value 都是 String ,通常用于配置文件的读取
- TreeMap:实现了 SortedMap 接口(是 Map 的子接口),可以对 Key 自动排序
HashMap
package com.test3;
import java.util.HashMap;
/**
* HashMap使用
* 存储结构:哈希表(数组+链表+红黑树)
*/
public class HashMapTest {
public static void main(String[] args) {
HashMap<Students,String> stu = new HashMap<>();
//添加元素
Students s1 = new Students("叶凡",100);
Students s2 = new Students("姬皓月",90);
Students s3 = new Students("黑皇",80);
stu.put(s1,"地球");
stu.put(s2,"北斗");
stu.put(s3,"紫薇");
System.out.println(stu);//{Students{name='姬皓月', age=90}=北斗, Students{name='黑皇', age=80}=紫薇, Students{name='叶凡', age=100}=地球}
stu.put(new Students("黑皇",80),"北斗");
System.out.println(stu);//重写了equals和hashcode方法,所以添加失败
//删除、遍历、判断和上面一样
}
}
TreeMap
public class TreeMapTest {
public static void main(String[] args) {
TreeMap<Students,String> treeMap = new TreeMap<>();
//添加元素
Students s1 = new Students("叶凡",100);
Students s2 = new Students("姬皓月",90);
Students s3 = new Students("黑皇",80);
treeMap.put(s1,"地球");
treeMap.put(s2,"北斗");
treeMap.put(s3,"紫薇");
System.out.println(treeMap);
}
}
这里运行会直接报错:
Exception in thread "main" java.lang.ClassCastException: com.test3.Students cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at com.test3.TreeMapTest.main(TreeMapTest.java:16)
因为TreeMap是红黑树存储结构,需要进行数据比较,所以我们要在students类中实现Comparable接口:
public class Students implements Comparable<Students>
@Override
public int compareTo(Students o) {
//这里定义根据年龄大小来比较
int n2 = this.age-o.getAge();
return n2;
}
现在再运行刚才的代码,就可以添加成功得到结果:
{Students{name='黑皇', age=80}=紫薇, Students{name='姬皓月', age=90}=北斗, Students{name='叶凡', age=100}=地球}
或者不在类中实现,也可以:
TreeMap<Students,String> treeMap = new TreeMap<>(new Comparator<Students>() {
@Override
public int compare(Students o1, Students o2) {
return 0;
}
});
删除也是如此:
//删除
treeMap.remove(new Students("黑皇",80));//这里只比较对象中的年龄,所以只要年龄一致,就能删除
System.out.println(treeMap);//{Students{name='姬皓月', age=90}=北斗, Students{name='叶凡', age=100}=地球}
Collections工具类
package com.test3;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Collections工具类演示
*/
public class CollectionsTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(12);
list.add(34);
list.add(32);
list.add(22);
//sort排序
Collections.sort(list);
System.out.println(list);//[12, 22, 32, 34]
//binarySearch二分查找
int i = Collections.binarySearch(list,34);
System.out.println(i);//3
//copy复制
List<Integer> dest = new ArrayList<>();
for (int j = 0; j < list.size(); j++) {
dest.add(0);
}
Collections.copy(dest,list);//直接copy会报错,因为两个集合的大小不一样,所以要用for先把两个集合大小保持一致
System.out.println(dest);//[12, 22, 32, 34],加了for后copy成功
//reverse反转
Collections.reverse(list);
System.out.println(list);//[34, 32, 22, 12]
//shuffle 打乱
Collections.shuffle(list);
System.out.println(list);//[32, 12, 22, 34]
//集合转数组
Integer[] arr = list.toArray(new Integer[0]);
System.out.println(arr.length);//4
System.out.println(Arrays.toString(arr));//[12, 22, 34, 32]
//数组转集合
String[] name = {"a", "s","d","x"};
//此集合是一个受限集合,不能添加不能删除
List<String> list1 = Arrays.asList(name);
System.out.println(list1);//[a, s, d, x]
//基本类型数组转集合时,需要修改为包装类型
// int[] nums = {1,2,3,4,5};
// List<int[]> list2 = Arrays.asList(nums);
// System.out.println(list2);//[[I@4554617c]
Integer[] nums = {1,2,3,4,5};
List<Integer> list2 = Arrays.asList(nums);
System.out.println(list2);//[1, 2, 3, 4, 5]
}
}
Properties 集合
基本使用
package com.test3;
import java.io.PrintWriter;
import java.util.Properties;
import java.util.Set;
public class PropertiesTest {
public static void main(String[] args) throws Exception {
//创建集合
Properties properties = new Properties();
//添加数据
properties.setProperty("username","张三");
properties.setProperty("age","20");
System.out.println(properties.toString()); //{age=20, username=张三}
//遍历
Set<String> pronames = properties.stringPropertyNames();
for (String s : pronames){
System.out.println(s+"======"+properties.getProperty(s));
}
结果:
{age=20, username=张三}
age======20
username======张三
Process finished with exit code 0
和流有关的用法
list方法
PrintWriter pw = new PrintWriter("C:\\Users\\LDH\\Desktop\\test.txt");
properties.list(pw);
pw.close();
结果:
store方法 (保存)
FileOutputStream fos = new FileOutputStream("C:\\Users\\LDH\\Desktop\\test3.properties");
properties.store(fos, "注释");
fos.close();
结果:
load方法 (加载)
Properties properties1 = new Properties();
FileInputStream fis = new FileInputStream("C:\\Users\\LDH\\Desktop\\test3.properties");
properties1.load(fis);
fis.close();
System.out.println(properties1.toString());
结果:
{age=20, username=张三}