Java入门级教程16——集合
Java集合分类:
1. Collection接口
1.1 List接口 可以重复元素
具体的实现类:
1.1.1 ArrayList实现类 底层是用数组实现的 线程非同步的
package com.hy.demo3;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;public class Test {public static void main(String[] args) {// 创建一个ArrayListCollection c1 = new ArrayList();List c2 = new ArrayList();ArrayList lists = new ArrayList();// 添加lists.add(10);lists.add("20");lists.add(true);lists.add(true);// 大小System.out.println("lists长度为:" + lists.size());// 包含System.out.println("是否包含true:" + lists.contains(true));System.out.println("是否包含20:" + lists.contains(20));// String类的方法String s = new String("我养了一只小鸟🐦");System.out.println("是否包含我:" + s.contains("我"));System.out.println("------------------------------");// 遍历System.out.println("遍历结果为:");for(int i = 0;i < lists.size();i++) {System.out.println(lists.get(i));}System.out.println("------------------------------");// 打印数组[0]System.out.println("lists.get(0)的值为:" + lists.get(0));// 更新lists.set(0, "张三");System.out.println("------------------------------");// 遍历System.out.println("遍历结果为:");for (int i = 0; i < lists.size(); i++) {System.out.println(lists.get(i));}System.out.println("------------------------------");// 删除lists.remove(0);// 遍历System.out.println("遍历结果为:");for (int i = 0; i < lists.size(); i++) {System.out.println(lists.get(i));}System.out.println("------------------------------");// 按值查找对应下标System.out.println(lists.indexOf("20")); // 0// 判断是否为空System.out.println(lists.isEmpty());// 清空lists.clear();// 判断是否为空System.out.println(lists.isEmpty());}}
输出结果:
lists长度为:4
是否包含true:true
是否包含20:false
是否包含我:true
------------------------------
遍历结果为:
10
20
true
true
------------------------------
lists.get(0)的值为:10
------------------------------
遍历结果为:
张三
20
true
true
------------------------------
遍历结果为:
20
true
true
------------------------------
0
false
true
// 解决线程非同步问题
package com.hy.demo18;import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class Test implements Runnable {CountDownLatch cd;static ArrayList list = new ArrayList();// static LinkedList list = new LinkedList();static List list1;public Test(CountDownLatch cd) {this.cd = cd;// 利用Collections的synchronizedList方法// 通过工具类将非线程安全的 list 包装为线程安全的列表// (所有方法加同步锁,避免多线程并发修改异常)list1 = Collections.synchronizedList(list);}public void run() {for (int i = 0; i < 100; i++) {// synchronized或Lock
// synchronized (this) {
// list.add(i);
// }list1.add(i);}cd.countDown();}public static void main(String[] args) {CountDownLatch cd = new CountDownLatch(4);Test t = new Test(cd);new Thread(t).start();new Thread(t).start();new Thread(t).start();new Thread(t).start();try {cd.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("这个集合的大小为:" + list.size()); // 400}}
//
package com.hy.demo17;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class Test {public static void main(String[] args) {// 泛型<引用类型>ArrayList lists = new ArrayList();lists.add(10);lists.add(20);lists.add(5);// 反转集合// System.out.println(lists); // [10, 20, 5]// Collections.reverse(lists);// System.out.println(lists); // [5, 20, 10]// Arrays.asList(lists);// System.out.println(lists); // 不变// Collections.reverseOrder();// System.out.println(lists); // 不变// 最大值// System.out.println(Collections.max(lists));// 排序// Collections.sort(lists);// System.out.println(lists);// 将集合lists转换为Object数组,然后对数组进行「降序排序」// 排序的是数组,而非原集合Object[] objs = lists.toArray();Arrays.sort(objs, Collections.reverseOrder());System.out.println(lists);for(Object obj : objs){System.out.println(obj);}}
}
1.创建集合并添加元素:
创建了一个未指定泛型的 ArrayList(原始类型),添加了三个整数 10、20、5。此时集合内容为:[10, 20, 5]。
反转集合(Collections.reverse()):
调用 Collections.reverse(lists) 对集合元素进行反转,反转后集合内容变为:[5, 20, 10]。
因此这一步输出:[5, 20, 10]。
2.Arrays.asList(lists) 调用:
Arrays.asList() 方法的作用是将数组转换为固定大小的 List,但这里传入的参数是一个 ArrayList 对象(集合),而非数组。
此时该方法会将整个 lists 集合作为单个元素,放入一个新的 List 中(新集合内容为 [[5, 20, 10]]),但原 lists 集合本身不会被修改。
因此这一步输出 lists 仍为:[5, 20, 10]。
3.Collections.reverseOrder() 调用:
该方法的作用是返回一个 “反转自然排序” 的比较器(Comparator),但它不会直接修改集合,只是提供一个用于排序的规则对象。
由于没有用这个比较器对集合进行排序操作,lists 内容保持不变,仍为:[5, 20, 10]。
因此这一步输出:[5, 20, 10]。
4.获取集合最大值(Collections.max()):
Collections.max(lists) 会根据元素的自然排序(这里是整数的大小)找出集合中的最大元素。
集合中元素为 5、20、10,最大值是 20,因此输出:20。
1.1.2 Vector 实现类 底层是用数组实现的 线程同步的
// 1. ArrayList是非线程同步安全,Vector是线程同步安全
package com.hy.demo2;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;public class Test {public static void main(String[] args) {// List接口下面有具体的实现类:ArrayList、Vector、LinkedList的实现类// ArrayList、Vector底层都是用数组实现的// ArrayList是非线程同步安全ArrayList lists1 = new ArrayList();lists1.add(20);// Vector是线程同步安全,方法是用synchronized修饰的Vector v1 = new Vector();v1.add(20);//LinkedList底层都是用链表实现的LinkedList list2 = new LinkedList();list2.addFirst(1);}
}
package com.hy.demo4;import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;public class Test implements Runnable {// 闭锁CountDownLatch cd;//ArrayList是线程非安全// static ArrayList lists = new ArrayList();static Vector lists = new Vector();public Test(CountDownLatch cd) {this.cd = cd;}public void run() {for (int i = 0; i < 100; i++) {lists.add(i); // 若是ArrayList则大概率报错,抛出数组下标越界异常// 解决方式1:// synchronized (this) {// lists.add(i);// }// 解决方式2:// 使用Vector}cd.countDown();}public static void main(String[] args) {CountDownLatch cd = new CountDownLatch(3);Test t = new Test(cd);new Thread(t).start();new Thread(t).start();new Thread(t).start();try {// cd.await():是 CountDownLatch 类的核心方法,// 作用是:让当前线程进入阻塞状态,等待 CountDownLatch 的计数器减为 0 后再继续执行cd.await();System.out.println("最后三个线程的总和为:" + lists.size());} catch (InterruptedException e) {e.printStackTrace();}}}
// 2. ArrayList与Vector对比
package com.hy.demo5;import java.util.ArrayList;
import java.util.Vector;public class Test {public static void main(String[] args) {/*** ArrayList和Vector区别* * 共同点是:底层是用数组来实现的。* * 不同点是:* * 1.初始化的大小不一样,ArrayList是空的,Vector是默认大小是10;* * 2. ArrayList是线程非安全的,Vector是线程安全的。* * */ArrayList lists = new ArrayList();Vector v = new Vector();}}
1.1.3 LinkedList实现类 底层是用链表来实现的
//
package com.hy.demo6;import java.util.LinkedList;public class Test {public static void main(String[] args) {LinkedList lists = new LinkedList();lists.add(10);lists.add(20);lists.add(30);System.out.println(lists.get(1));}}
// LinkedList也可以使用栈的数据数据结构特点
package com.hy.demo6;import java.util.LinkedList;public class Test1 {public static void main(String[] args) {// LinkedList也可以使用栈的数据结构特点// 栈:先进后出,后进先出LinkedList lists = new LinkedList();lists.push(10);lists.push(20);lists.push(30);while (!lists.isEmpty()) {System.out.println(lists.pop());}}}
package com.hy.demo2;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;public class Test {public static void main(String[] args) {//List接口下面有具体的实现类:ArrayList、Vector、LinkedList的实现类//ArrayList、Vector底层都是用数组实现的ArrayList lists1 = new ArrayList();lists1.add(20);Vector v1 = new Vector();v1.add(20);//LinkedList底层都是用链表实现的LinkedList list2 = new LinkedList();list2.addFirst(1);}
}
// ArrayList与LinkedList性能测试对比
package com.hy.demo7;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class Test {// ArrayList底层的数据结构是数组,数组的数据结构特点:遍历快,增删改慢// [1,2,3,4,5,6,7]// LinkedList底层的数据结构是链表,链表的数据结构特点:遍历慢,增删改快// 前索引1-元素1-后索引1 前索引2-元素2-后索引 2 前索引3-元素3-后索引 3public static void addData(List lists) {// 性能测试long startTime = System.currentTimeMillis();int i = 0;while (i < 200000) {Object obj = new Object();lists.add(0, obj);i++;}long endTime = System.currentTimeMillis();System.out.println("花费的时间为:" + (endTime - startTime));}public static void main(String[] args) {//addData(new ArrayList());//花费的时间为:2603addData(new LinkedList()); //花费的时间为:6}}
// ArrayList与LinkedList遍历时长对比
package com.hy.demo8;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class Test {public static void queryData(List lists) {long startTime = System.currentTimeMillis();for (int i = 0; i < lists.size(); i++) {// 获取lists.get(i);}long endTime = System.currentTimeMillis();System.out.println("遍历花费的时间为:" + (endTime - startTime));}public static void main(String[] args) {// ArrayList lists = new ArrayList(); // 6LinkedList lists = new LinkedList(); // 时间很长for (int i = 0; i < 500000; i++) {lists.add(i);}queryData(lists);// ArrayList的6毫秒 //遍历花费的时间为:85212/1000 = 85.212}}
// 与迭代器遍历对比
package com.hy.demo8;import java.util.Iterator;
import java.util.LinkedList;public class Test1 {public static void queryData1(LinkedList lists) {long startTime = System.currentTimeMillis();for (int i = 0; i < lists.size(); i++) {// 获取lists.get(i);}long endTime = System.currentTimeMillis();System.out.println("遍历花费的时间为:" + (endTime - startTime));}public static void queryData2(LinkedList lists) {long startTime = System.currentTimeMillis();//迭代器遍历Iterator its = lists.iterator();while(its.hasNext()){its.next();}long endTime = System.currentTimeMillis();System.out.println("遍历花费的时间为:" + (endTime - startTime));}public static void main(String[] args) {LinkedList lists1 = new LinkedList();for (int i = 0; i < 200000; i++) {lists1.add(i);}// queryData1(lists1);// //一般for遍历花费的时间为:12060/1000 =12秒queryData2(lists1);//迭代器遍历 遍历花费的时间为:4毫秒}}
// List本身不能过滤重复,那该如何过滤重复?
package com.hy.demo20;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class Test {public static void main(String[] args) {List<String> lists = new ArrayList<String>();lists.add("张三");lists.add("李四");lists.add("张三");// List集合是不能过滤重复的,现在要求你过滤重复List<String> lists1 = new ArrayList<String>();for (String s : lists) {if (!lists1.contains(s)) {lists1.add(s);}}System.out.println(lists1); // [张三, 李四]}}
1.2 Set接口 不可以重复元素
HashSet TreeSet LinkedHashSet
package com.hy.demo1;import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;public class Test1 {public static void main(String[] args) {// Collection接口下面有两个子类接口:// 1. List接口,可以有重复元素// 2. Set接口 不能有重复元素List lists = new ArrayList();lists.add(10);lists.add(20);lists.add(10);System.out.println(lists.size()); // 3System.out.println("------------");HashSet set = new HashSet();set.add(10);set.add(20);set.add(10);System.out.println(set.size()); // 2}}
1.3 学完后运用于数据库
package com.hy.demo9;// JavaBean,Java数据模型,对应数据库中的表
public class Stu {private int sid;private String sname;private String saddress;public int getSid() {return sid;}public void setSid(int sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public String getSaddress() {return saddress;}public void setSaddress(String saddress) {this.saddress = saddress;}
}
// 不同的Dao
package com.hy.demo9;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;public class Dao {Connection conn; public Dao() {try {Class.forName("com.mysql.cj.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jk202508","root","Hy61573166!!!");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}public Object[][] queryDatas(String tableName) {Object[][] datas = null; // 用于存放最终查询结果的二维数组// 第一个SQL:查询表的记录总数(用于初始化二维数组的行数)String sql = "select count(*) from " + tableName;try {// 创建PreparedStatement对象(用于执行SQL语句)PreparedStatement pstmt = conn.prepareStatement(sql);// 执行查询,返回结果集(ResultSet)ResultSet rs = pstmt.executeQuery();int count = 0; // 记录总数while (rs.next()) { // 遍历结果集(此处只有一条记录,即总数)count = rs.getInt(1); // 获取第一列的值(即count(*)的结果)}System.out.println("count为:" + count); // 打印记录总数// datas = new Object[count][];// 数据库差异性,oracle这个rs结合集是默认不可滚动,mysql的rs的结果集是可滚动// rs.beforeFirst();// 第二个SQL:查询表中所有记录String sql1 = "select * from " + tableName;PreparedStatement pstmt1 = conn.prepareStatement(sql1);ResultSet rs1 = pstmt1.executeQuery(); // 执行查询,获取所有记录的结果集// 获取结果集元数据(用于获取列数)ResultSetMetaData rsmd = rs1.getMetaData();int columns = rsmd.getColumnCount(); // 获取表的列数System.out.println("列数为:" + columns); // 打印列数// 初始化二维数组:行数=记录总数(count),列数=表的列数(columns)datas = new Object[count][columns];// 把数据赋值给二维数组int row = 0; // 记录当前行索引(从0开始)// 遍历所有记录(rs1.next()为true表示有下一条记录)while (rs1.next()) {// 遍历每一列(i从0到columns-1)for (int i = 0; i < columns; i++) {// 获取第i+1列的值(JDBC列索引从1开始),存入datas[row][i]datas[row][i] = rs1.getObject(i + 1);}row++; // 移动到下一行}} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {// 关闭数据库连接(避免资源泄漏)if (null != conn) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}return datas; // 返回填充好数据的二维数组}public static void main(String[] args) {Dao dao = new Dao();Object[][] datas = dao.queryDatas("t_emp");for (int i = 0; i < datas.length; i++) {for (int j = 0; j < datas[i].length; j++) {System.out.print(datas[i][j] + ",");}System.out.println();}}}
package com.hy.demo9;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;public class Dao1 {Connection conn;public Dao1() {try {Class.forName("com.mysql.cj.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jk202508", "root", "Hy61573166!!!");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}public LinkedList<Stu> queryDatas(String tableName) {String sql = "select * from " + tableName;// <类型>,同一个类型,映射数据库中表的字段LinkedList<Stu> lists = new LinkedList<Stu>();try {PreparedStatement pstmt = this.conn.prepareStatement(sql);ResultSet rs = pstmt.executeQuery();while (rs.next()) {Stu s = new Stu();s.setSid(rs.getInt(1));s.setSname(rs.getString(2));s.setSaddress(rs.getString(3));lists.add(s);}} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (null != conn) {try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}return lists;}public static void main(String[] args) {Dao1 dao = new Dao1();LinkedList<Stu> lists = dao.queryDatas("t_stus");for (Stu s : lists) {System.out.println(s.getSid() + "," + s.getSname() + "," + s.getSaddress());}}}
* 数据存放都是采用数组,原始的数组构建来说,不适合现在项目存放数据的要求。固定机制
*
* 数据存放都采用集合,动态机制,自动扩容机制,扩容大小不一样。 1.5/2
//可以过滤重复
package com.hy.demo19;import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;public class Test implements Runnable {CountDownLatch cd;static HashSet set = new HashSet();static Set set1;public Test(CountDownLatch cd) {this.cd = cd;set1 = Collections.synchronizedSet(set);}public void run() {for (int i = 0; i < 100; i++) {// synchronized或Lock
// synchronized (this) {
// list.add(i);
// }set1.add(i);}cd.countDown();}public static void main(String[] args) {CountDownLatch cd = new CountDownLatch(4);Test t = new Test(cd);new Thread(t).start();new Thread(t).start();new Thread(t).start();new Thread(t).start();try {cd.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("这个集合的大小为:" + set1.size()); // 10}}
//HashSet 不保证元素的存储 / 迭代顺序(既不是插入顺序,也不是自然排序),其顺序由元素的哈希值(hashCode())和哈希表的结构决定。
package com.hy.demo21;import java.util.HashSet;
import java.util.LinkedHashSet;public class Test {public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet<String>();set.add("one");set.add("two");set.add("three");set.add("four");System.out.println(set);System.out.println("-------------");HashSet<String> set1 = new HashSet<String>();set1.add("one");set1.add("two");set1.add("three");set1.add("four");System.out.println(set1);}}
输出结果:
[one, two, three, four]
-------------
[four, one, two, three]
2. Map接口
2.1 具体实现类:
HashMap, 线程非同步的
Hashtable,线程同步的 (全部锁住)
concurrentHashMap;线程同步的(分段锁机制),性能优化角度
// 1.
package com.hy.demo22;import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;/*** Map接口* * 一个键值对的接口:key:value* * 直接实现子类:* HashMap、Hashtable 一个线程非安全,一个是线程安全(全部加锁,锁定范围太大,降低了性能)* ConcurrentHashMap 一个是线程安全(分段锁,拆分了锁的范围,提高了性能)* @author hy**/public class Test {public static void main(String[] args) {HashMap map1 = new HashMap();// HashMap键和值可以为空map1.put(null, null);System.out.println(map1.get(null));System.out.println("---------------");// Hashtable键和值都不能为空Hashtable map2 = new Hashtable();map2.put(null, null);System.out.println(map2.get(null));System.out.println("---------------");ConcurrentHashMap map3 = new ConcurrentHashMap();// ConcurrentHashMap键和值都不能为空map3.put(null, null);System.out.println(map3.get(null));}}
// 2.
核心区别:元素顺序的维护
特性 | HashSet | LinkedHashSet |
---|---|---|
继承关系 | 直接实现 Set 接口 | 继承 HashSet ,间接实现 Set 接口 |
底层结构 | 仅基于哈希表(数组 + 链表 / 红黑树) | 哈希表 + 双向链表(额外维护插入顺序) |
元素顺序 | 不保证任何顺序 | 保证插入顺序(迭代时与添加顺序一致) |
性能 | 插入 / 查询效率略高(无链表维护开销) | 性能略低于 HashSet (需维护链表结构) |
3. 队列
暂不讲解
4.Collections
Collection和Collections是啥关系?
Collection是一个集合的接口,是一个父类接口。
Collections是集合的工具类,是一个具体的实现类,工具类提供了大量的工具方法