文章目录
- 一、与集合相关的数据结构
- 二、List集合
-
- 2.1 List集合概述
- 2.2 List接口中带索引特有的方法
- 2.3 遍历List集合的三种方法
- 三、List接口的子类(实现类)
-
- 3.1 ArrayList集合(ArrayList类型的对象)
- 3.2 LinkedList集合(LinkedList类型的对象)
- 3.3 Vector集合(Vector类型的对象)(了解)
- 四、Set接口
-
- Set接口概述
- 五、Set接口的子类(实现类)
-
- 5.1 HashSet集合
-
- 5.1.1 HashSet存储数据的结构——哈希表
- 5.1.2 HashSet集合概述和特点
- 5.1.3 HashSet保证元素唯一性源码分析
- 5.1.4 常见数据结构之【哈希表】
- 5.2 LinkedHashSet集合概述和特点(继承自HashSet)
- 5.3 TreeSet集合概述和特点
-
- 5.3.1 自然排序Comparable接口的使用
- 5.3.2 比较器排序Comparator接口的使用
- 练习
一、与集合相关的数据结构
回到目录
- 栈:是一种先进后出的模型。
- 队列:是一种先进先出的模型。
- 数组:查询快,添删慢的模型。
- 链表:对于数组来说,是一种增删快,查询慢的模型。
- 红黑树
集合的继承关系
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPB1EeFpmT4lEROBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2UjM4IzNxQTM1ETNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
二、List集合
回到目录
2.1 List集合概述
java.util.List
接口继承自
Collection
接口,是单列集合的一个重要分支,一般习惯将实现了List接口的对象称为List集合。
List接口的三大特点:
- 有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123);
- 有索引,包含了一些带索引的方法;
- 允许存储重复的元素。
2.2 List接口中带索引特有的方法
- public void add(int index, E element):将指定的元素,添加到该集合中的指定位置上;
- public E get(int index):返回集合中指定位置的元素;
- public E remove(int index):移除列表中指定位置的元素,返回的是被移除的元素;
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
注意:
操作索引的时候,一定要防止索引越界异常。
- IndexOutOfBoundsException:索引越界异常,集合中会报出这样的异常
- ArrayIndexOutOfBoundsException:数组索引越界异常
- StringIndexOutOfBoundsException:字符串索引越界异常
2.3 遍历List集合的三种方法
- 普通for循环(因为List集合有索引,可以用for循环遍历);
- 迭代器遍历List集合;
- 增强for循环
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
java.util.List接口 extends Collection接口
List接口的特点:
1.有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123)
2.有索引,包含了一些带索引的方法
3.允许存储重复的元素
List接口中带索引的方法(特有)
- public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
- public E get(int index):返回集合中指定位置的元素。
- public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
注意:
操作索引的时候,一定要防止索引越界异常
IndexOutOfBoundsException:索引越界异常,集合会报
ArrayIndexOutOfBoundsException:数组索引越界异常
StringIndexOutOfBoundsException:字符串索引越界异常
*/
public class Demo01List {
public static void main(String[] args) {
// 通过多态的写法,创建一个List集合对象
List<String> list = new ArrayList<>(); // List集合的泛型是字符串
//使用add方法往集合中添加字符串元素
list.add("古力娜扎");
list.add("迪丽热巴");
list.add("古力娜扎");
list.add("玛尔扎哈");
list.add("玛尔扎哈");
System.out.println(list); // [古力娜扎, 迪丽热巴, 古力娜扎, 玛尔扎哈, 玛尔扎哈]
// 而且打印的不是地址值,说明重写了toString方法
// public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
// 在 古力娜扎和玛尔扎哈 之间添加一个cxk
list.add(3, "cxk");
System.out.println(list); // [古力娜扎, 迪丽热巴, 古力娜扎, cxk, 玛尔扎哈, 玛尔扎哈]
// public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
// 移除元素cxk,cxk的索引是3
String removeE = list.remove(3); // removeE 得到的是被移除的元素
System.out.println("被移除的元素:" + removeE); // 被移除的元素:cxk
System.out.println(list); // [古力娜扎, 迪丽热巴, 古力娜扎, 玛尔扎哈, 玛尔扎哈]
// public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
// 把第一个“古力娜扎”, 替换为“萨扬娜拉”
String setE = list.set(0, "萨扬娜拉"); // setE 得到的是被替换前的元素
System.out.println("被替换的元素:" + setE); // 被替换的元素:古力娜扎
System.out.println(list); // [萨扬娜拉, 迪丽热巴, 古力娜扎, 玛尔扎哈, 玛尔扎哈]
System.out.println("==========================");
// List集合遍历的3种方式
// 使用普通的for循环
for (int i = 0; i < list.size(); i++) {
//public E get(int index):返回集合中指定位置的元素。
String s = list.get(i);
System.out.println(s);
}
System.out.println("==========================");
// 使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) { // 集合中的下一个是否有元素
String s = it.next(); // s是下一个元素
System.out.println(s);
}
System.out.println("==========================");
// 使用增强for
for (String s : list) {
System.out.println(s);
}
// 索引越界异常
String r = list.get(5);
System.out.println(r); // java.lang.IndexOutOfBoundsException: Index 5 out of bounds for length 5
}
}
三、List接口的子类(实现类)
回到目录
3.1 ArrayList集合(ArrayList类型的对象)
java.util.ArrayList
集合数据存储的结构是【数组结构】,增删比较慢,查询快。通常我们使用最多的功能就是查询数据、遍历数据,所以
ArrayList
是最常用的集合。
ArrayList
集合不是同步的(不是同步就是多线程),效率比较高。
import java.util.ArrayList;
import java.util.Iterator;
/*
ArrayList集合存储学生对象, 用三种方式遍历, (Student类里面私有成员变量为name, age)。
*/
public class ArrayListDemo{
public static void main(String[] args) {
// 创建ArrayList集合
ArrayList<Student> array = new ArrayList<>();
// 创建学生对象
Student s1 = new Student("迪丽热巴",25);
Student s2 = new Student("古力娜扎",26);
Student s3 = new Student("玛尔扎哈",40);
// 把学生添加到集合
array.add(s1);
array.add(s2);
array.add(s3);
// 迭代器遍历:集合特有的遍历方式
Iterator<Student> it = array.iterator();
while(it.hasNext()){
Student s = it.next();
System.out.println(s.getName() + "," + s.getAge());
}
System.out.println("==================================");
// 普通for:带索引的遍历方式
for (int i = 0; i < array.size(); i++) {
Student s = array.get(i);
System.out.println(s.getName() + "," + s.getAge());
}
System.out.println("==================================");
// 增强for:最方便的遍历方式
for(Student s : array){
System.out.println(s.getName() + "," + s.getAge());
}
}
}
3.2 LinkedList集合(LinkedList类型的对象)
java.util.LinkedList
集合数据存储的结构是【链表结构】,增删快,查询慢。也是多线程的。
LinkedList实现类中提供了大量特有的【首尾操作】方法:
- public void addFirst(E e):将指定元素插入此列表的开头。
- public void addLast(E e):将指定元素添加到此列表的结尾。
- public void push(E e):将元素推入此列表所表示的堆栈。 【这个push方法等效于addFist方法】
- public E getFirst():返回此列表的第一个元素。
- public E getLast():返回此列表的最后一个元素。
- public E removeFirst():移除并返回此列表的第一个元素。
- public E removeLast():移除并返回此列表的最后一个元素。
- public E pop():从此列表所表示的堆栈处弹出一个元素。 【这个pop方法等效于removeFirst方法】
- public boolean isEmpty():如果列表不包含元素,则返回true。
使用LinkedList集合要注意:不能使用多态(多态,完成了向上转型(转为List接口了),不能使用实现类(LinkedList)特有的方法)
LinkedList集合是一个实现类,直接new一个对象就可以了。
创建LinkedList集合:
LinkedList<String> linked = new LinkedList<>();
以删除集合元素的方法为例:(增删改查都差不多)
import java.util.LinkedList;
public class Demo02LinkedList {
public static void main(String[] args) {
show1();
}
private static void show1() {
// 创建LinkedList集合对象,LinkedList集合是一个实现类,直接new对象
LinkedList<String> linked = new LinkedList<>();
// 使用add方法往集合中添加元素
linked.add("迪丽热巴");
linked.add("古力娜扎");
linked.add("玛尔扎哈");
System.out.println(linked); // [迪丽热巴, 古力娜扎, 玛尔扎哈]
// pop方法等效于removeFirst()方法
String first = linked.pop();
System.out.println("被移除的第一个元素:" + first); // 被移除的第一个元素:迪丽热巴
// public E removeLast():移除并返回此列表的最后一个元素。
String last = linked.removeLast();
System.out.println("被移除的最后一个元素:" + last); // 被移除的最后一个元素:玛尔扎哈
System.out.println(linked); // [古力娜扎]
}
}
3.3 Vector集合(Vector类型的对象)(了解)
Vector 类可以实现可增长的【对象数组】,与新 collection 实现不同,Vector 是同步的(单线程,速度慢)。在JDK1.2+,被ArrayList集合取代了。
- Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的;
- Vector 的 elements 方法返回的 Enumeration(枚举) 不是 快速失败的。
四、Set接口
回到目录
java.util.Set
接口和
java.util.List
接口一样,都是继承于
Collection
接口。所以,Set接口的方法继承自Collection接口,所以常用的方法是一致的,之前在Collection接口中讲了常用方法,这里就不再重复了。
Set接口概述
Set接口的特点:
- 不允许存储重复的元素;
- 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
五、Set接口的子类(实现类)
接口不能直接创建对象,要用到Set接口的实现类,Set接口有两个实现类:
java.util.HashSet
集合和
java.util.LinkedHashSet
集合。
5.1 HashSet集合
回到目录
HashSet集合的特点:
- 【不允许存储重复】的元素;
- 【无索引】,没有带索引的方法,也不能使用普通的for循环遍历;
- 是一个【无序】的集合,存储元素和取出元素的顺序有可能不一致,对集合的迭代顺序不作任何保证;
- 底层是一个【哈希表结构】(查询的速度非常的快)。
HashSet集合的遍历方法有两个:(没有索引,不能用普通for)
- Iterator迭代器;
- 增强for
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Demo01Set {
public static void main(String[] args) {
// 多态的写法可以,不用多态的写法也可以,直接用通过HashSet实现类创建对象—— HashSet<String> set = new HashSet<>();
Set<String> set = new HashSet<>();
// 使用add方法往集合中添加元素
set.add("迪丽热巴");
set.add("古力娜扎");
set.add("玛尔扎哈");
set.add("迪丽热巴");
//使用迭代器遍历集合,Collection接口所有的实现类里都有iterator方法
Iterator<String> it = set.iterator(); // 调用iterator()方法,返回一个Iterator接口的实现类对象。
while (it.hasNext()){
String s = it.next(); // 快捷键【Ctrl+Alt+V】
System.out.println(s); // 玛尔扎哈 迪丽热巴 古力娜扎 ———— 【没有顺序,没有重复的元素】
}
System.out.println("====================");
//使用增强for遍历集合
for (String a : set) {
System.out.println(a);
}
}
}
5.1.1 HashSet存储数据的结构——哈希表
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。
在Object类中的 hashCode()
方法,可以获取对象的哈希值。**
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的;
- 默认情况下(没重写hashCode方法),不同对象的哈希值是不同的;
- 通过重写hashCode方法,可以实现不同对象的哈希值相同。(String类中重写了Obejct类中的hashCode方法)
int hashCode() :返回该对象的哈希码值。
hashCode方法的源码:
public native int hashCode(); // native:代表该方法调用的是本地操作系统的方法
定义一个Person类(默认继承于Object类):
public class Person /*extends Object*/{
}
使用Person类:
public class Demo01HashCode {
public static void main(String[] args) {
// Person类继承了Object类,所以可以使用Object类的hashCode方法
Person p1 = new Person();
int h1 = p1.hashCode();
System.out.println(h1); // 1967205423
Person p2 = new Person();
int h2 = p2.hashCode();
System.out.println(h2); // 42121758
// 不同对象哈希值不同
/*
toString方法的源码:
return getClass().getName() + "@" + Integer.toHexString(hashCode());
*/
System.out.println(p1); // 包名@75412c2f
System.out.println(p2); // 包名@282ba1e
System.out.println(p1 == p2); // false
/*
String类的哈希值
String类中重写了Obejct类中的hashCode方法
*/
// 字符串常量池,用的是一个对象,地址值也相同
System.out.println("Hello".hashCode()); // 69609650
System.out.println("Java".hashCode()); // 2301506
String s1 = new String("abc");
System.out.println(s1.hashCode()); // 96354
System.out.println("abc".hashCode()); // 96354
// 特殊
System.out.println("重地".hashCode()); // 1179395
System.out.println("通话".hashCode()); // 1179395
}
}
5.1.2 HashSet集合概述和特点
HashSet集合特点:
- 底层数据结构是【哈希表】——( 哈希表是 数组+链表 )
- 对集合的迭代顺序不做保证,也就是说【不保证】存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用【普通for】遍历
- 由于是Set集合,所以是不包含重复元素的集合
HashSet集合练习:
import java.util.HashSet;
public class HashSetDemo01 {
public static void main(String[] args) {
// 创建HashSet对象
HashSet<String> hs = new HashSet<>();
// 添加对象
hs.add("迪丽热巴");
hs.add("古力娜扎");
hs.add("玛尔扎哈");
hs.add("玛尔扎哈");
// 增强for遍历
for (String s : hs) {
System.out.println(s);
}
}
}
5.1.3 HashSet保证元素唯一性源码分析
HashSet集合添加一个元素的过程:
HashSet集合存储元素:
-
要保证元素的唯一性,需要重写hashCode()和equals()方法(equals方法比较内容是否相同)
源码 :
// 创建HashSet对象
HashSet<String> hs = new HashSet<>();
// 添加对象
hs.add("迪丽热巴");
hs.add("古力娜扎");
hs.add("玛尔扎哈");
hs.add("玛尔扎哈");
-----------------------------------------------
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
// hash值和元素的hashCode()方法相关
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 如果哈希表未初始化,就对其进行初始化
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 根据对象的哈希值计算对象的存储位置,如果该位置没有元素,就存储元素
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
/*
存入的元素和以前的元素比较哈希值
如果哈希值不同,会继续向下执行,把元素添加到集合
如果哈希值相同,会调用对象的equals()方法比较
如果返回false, 会继续向下执行,把元素添加到集合
如果返回true, 说明元素重复,不存储
*/
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p ;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
5.1.4 常见数据结构之【哈希表】
哈希表 : (哈希表中没有重复的元素)
- JDK8之前, 底层采用【数组+链表】实现, 可以说是一个元素为链表的数组
- JDK8之后, 在长度比较长时, 底层实现了优化
对象的哈希值对16取余就是在哈希表(数组)中的索引位置。
当两对象间的哈希值相同时,比内容。如果内容也相同(重复元素),就不存储;如果内容不相同,就在数组中用链表连着。
练习:HashSet集合存储学生对象并遍历(要求:如果两对象的成员变量值相同,就认为是一个对象)
- 已经定义好了Student类,有私有成员变量name和age。
- 要重写Student类中的hashCode()和equals()方法!要不然,还是可以把相同的成员变量添加进去,快捷键自动生成。
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo02 {
public static void main(String[] args) {
// 创建HashSet集合对象
HashSet<Student> hs = new HashSet<>();
// 创建学生对象
Student s1 = new Student("迪丽热巴",20);
Student s2 = new Student("古力娜扎",21);
Student s3 = new Student("玛尔扎哈",30);
// 注意: s4引用的Student对象跟s1对象的成员变量的值是一样的,要视为一个对象, 不能把s4添加进去
Student s4 = new Student("迪丽热巴",20);
// 把学生添加到集合
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
// 用迭代器遍历集合
Iterator<Student> it = hs.iterator();
while(it.hasNext()){
Student a = it.next();
System.out.println(a.getName() + "," + a.getAge());
}
}
}
没有重写Student类中的equals()和hashCode()方法时,把重复的添加到HashSet集合中了:
自动生成,重写Student类的equals和hashCode方法后,重复的将被视为一个对象
Student类重写:
控制台输出:
5.2 LinkedHashSet集合概述和特点(继承自HashSet)
LinkedHashSet集合特点:
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 由链表保证元素有序,也就是说元素的【存储和取出顺序是一致的】
- 由哈希表保证元素的唯一,没有重复的元素
练习:用LInkedHashSet存储字符串并遍历
import java.util.Iterator;
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
public static void main(String[] args) {
// 创建LInkedHashSet集合对象
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
// 添加元素
linkedHashSet.add("迪丽热巴");
linkedHashSet.add("古力娜扎");
linkedHashSet.add("玛尔扎哈");
linkedHashSet.add("迪丽热巴");
// 迭代器遍历
Iterator<String> it = linkedHashSet.iterator();
while(it.hasNext()){
String a = it.next();
System.out.println(a);
}
System.out.println("===================");
// 增强for遍历
for (String s : linkedHashSet) {
System.out.println(s);
}
}
}
控制台输出:(输出和输入的顺序相同,哈希表保证了元素的唯一性)
5.3 TreeSet集合概述和特点
回到目录
TreeSet集合的特点:
-
元素有序,这里的排序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体的排序方式取决于构造方法
无参构造TreeSet():根据其元素的【自然排序】(从小到大)进行排序
带参构造TreeSet(Comparator comparator):根据指定的比较器进行排序
- 没有带索引的方法,所以不能使用普通for遍历
- 由于是Set集合,不包含重复元素的集合
TreeSet集合练习:存储整数并遍历
import java.util.TreeSet;
public class TreeSetDemo01 {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>(); // 由于调用的是无参构造,按照自然排序,从小到大排
// 添加元素
ts.add(10);
ts.add(50);
ts.add(40);
ts.add(20);
// 无重复元素
ts.add(20);
// TreeSet没得索引, 增强for遍历
for(Integer i : ts){
System.out.println(i);
}
}
}
5.3.1 自然排序Comparable接口的使用
需求:
- 存储学生对象并遍历,创建TreeSet集合使用【无参构造方法】——无参构造,直接Comparable接口
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论:
- 用TreeSet集合存储自定义对象,无参构造方法使用的是【自然排序】对元素进行排序的
- 自然排序,就是让元素所属的类(例子是Student类)实现Comparable接口,重写comparaTo(T o)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写,比如说年龄相同时,按照姓名排序。
Student类:
import java.util.Objects;
public class Student implements Comparable<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;
}
// 重写compareTo方法
@Override
public int compareTo(Student o) {
// return 0; 返回值如果是0,被认为是重复元素,就不会添加后面的元素了,只会有一个值
// return 1; 按照存储的顺序输出的
// return -1; 按照存储倒着输出
// 我们的需求是:按照 年龄从小到大排序(主要条件)
int num = this.age - o.age; // 按照年龄的升序【升序this放在前面】
// 换成 int num = o.age - this.age;就是按照年龄的降序来排列
// 年龄相同时,按照姓名的字母顺序排序
int num2 = num == 0 ? this.name.compareTo(o.name) : num;
return num2;
}
}
实现需求:
import java.util.TreeSet;
public class TreeSetDemo02 {
public static void main(String[] args) {
// 创建 TreeSet 集合
TreeSet<Student> ts = new TreeSet<>();
// 创建学生对象
Student s1 = new Student("ddd",23);
Student s2 = new Student("aaa",30);
Student s3 = new Student("ccc",21);
Student s4 = new Student("ddd",22);
Student s5 = new Student("kkk",22);
Student s6 = new Student("cxk",22);
Student s7 = new Student("cxk",22); // 因为重写了hashCode和equals方法,只能存一个cxk
// 把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
// 增强for遍历
for(Student s : ts){
System.out.println(s.getName() + "," + s.getAge());
}
}
}
5.3.2 比较器排序Comparator接口的使用
需求:
- 存储学生对象并遍历,创建TreeSet集合使用【带参构造方法】——Comparator
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论:
- 用TreeSet集合存储自定义对象,【带参构造方法】使用的是【比较器排序】的
- 比较器排序,就是,让集合构造方法接受Comparator的实现类对象,重写compare(T o1, T o2)方法
- 重写方法时,一定要注意排序规则必须按照要求的主、次要条件来写
学生类:
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;
}
}
import java.util.Comparator;
import java.util.TreeSet;
// 创建TreeSet集合使用【带参构造方法】
public class TreeSetDemo {
public static void main(String[] args) {
// 创建 TreeSet 集合,要使用【带参构造方法】,用【匿名内部类】实现Comparator接口
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// this.age - s.age
// s1, s2
int num = s1.getAge() - s2.getAge(); // 主要条件——年龄
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num; // 次要条件——姓名
// 比较s1和s2的年龄,相同就比较名字,都相同就认为是同一个,不加到集合里面
return num2;
}
});
// 创建学生对象
Student s1 = new Student("ddd", 23);
Student s2 = new Student("aa", 30);
Student s3 = new Student("cc", 21);
Student s4 = new Student("dd", 22);
Student s5 = new Student("kk", 22);
Student s6 = new Student("cxk", 22);
Student s7 = new Student("cxk", 22);
// 把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
// 增强for遍历
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
练习
题目:
编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,在控制台输出
思路:
- 创建Set集合(没有重复的元素)
- 创建随机数对象
- 判断集合长度是否小于10,小于10则产生一个随机数,添加到集合,回到3继续循环
- 遍历集合
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
// 创建Set集合,多态的写法
// Set<Integer> set = new HashSet<>(); // HashSet集合显示的结果没有顺序,TreeSet集合显示的结果有顺序
Set<Integer> set = new TreeSet<>(); // HashSet集合显示的结果没有顺序,TreeSet集合显示的结果有顺序
// 创建随机数对象
Random r = new Random();
// 判断集合的长度是否小于10
while (set.size()<10){
// 产生一个随机数,添加到集合
int number = r.nextInt(20)+1;
set.add(number);
}
// 增强for遍历集合
for(Integer i:set){
System.out.println(i);
}
}
}