单列集合根接口:java.util.Collection
多列集合根 接口:java.util.Map
Vector是基于数组的,线程安全。在容量不够的情况下,内存增长为原来的一倍;
ArrayList基于数组但是线程不安全,增长为原数组的50%。增删慢,查找快。
LinkedList是基于双向链表线程不安全的。增删快,查找慢
List和Set都是继承Collection接口的。
区别:List是⼀种有序、带索引、可以存放重复数据的集合
Set是⼀种⽆序、不带下标索引、不能存放重复数据的集合
boolean contains(Object o);//判断集合是否包含给定元素,借助equals方法。不是使用地址判断的
Collection c1 = new ArrayList<>();
String s1 = "hello";
String s2 = "world";
String s3 = new String("world");
c1.add(s1);
boolean f1 = c1.contains("hello");//true
f1 = c1.contains(s3);//true,s3是堆中临时new出来的和s1(存在字符串常量池中)地址不一样,但指向的内容一样,
Object[] toArray() //把集合存储到数组中
boolean containsAll(Collection> c);//判断当前集合中是否包含给定的集合的所有元素。
boolean retainAll(Collection> c)判断俩个集合中是否有相同的元素,如果有当前集合只保留相同元素,如果没有当前集合元素清空
要使用contains和remove方法是必须得重写equals方法
public static void main(String[] args) {
//创建学生对象
Student s1 = new Student("zs",12,"nan");
Student s2 = new Student("as",25,"nv");
Student s3 = new Student("zs" ,12,"nan");
Collection coll = new ArrayList<>();
coll.add(s1);
coll.add(s2);
System.out.println(coll.size());
System.out.println(coll);//s1和s3属性值相同,应该是同一个人
//判断s3是否存在
boolean f = coll.contains(s3);
System.out.println(f);//false 按理来说是存在的
//删除s3
boolean flag = coll.remove(s3);
System.out.println(flag);
//出现这种情况要重写equals来比较,重写之后f和flag都为true
}
class Student{
@Override
public boolean equals(Object obj){
if(this == obj)//this输入的值,obj原来的值
return true;
if(this == null)
return false;
if(getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if(age != other.age)
return false;
if(name == null){
if(other.name != null)
return false;
} else if (! name.equals(other.name)) {
return false;
}
return true;
}
}
toArray();
//将集合转化成数组
Object[] array = 集合引用.toArray();
//遍历数组
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
迭代器
1.获取迭代器对象
Iterator<集合元素类型> iterator = 集合对象.iterator();
//借助hasNext()和next()完成遍历
while(iteratro.hashNext()){
//获取集合元素
集合元素类型 变量名 = iterator.next();
//对集合元素进行输出
System.out.println(变量名);
}
foreach(Collection和其子类集合,数组,都可以用foreach循环遍历)
for(集合元素类型 变量名 : 集合) {
//操作元素变量
}
get(int index);//返回集合中指定位置的元素
set(int index, E element);//用指定元素替换集合中指定位置的元素,并返回被替代的旧元素。
add(int index, E element);//将指定的元素,添加到该集合中的指定位置上。
boolean addAll(int index, Collection extends E> c);//从指定位置开始,把另一个集合的所有元素添加进来
remove(int index);//移除列表中指定位置的元素, 并返回被移除的元素。
int indexOf(Object o);//查收指定元素在集合中的所有,从前往后查到的第一个元素(List集合可以重复存放数据)
int lastIndexOf(Object o);
List subList(int fromIndex, int toIndex);//根据指定开始和结束位置,截取出集合中的一部分数据
使用get方法
//遍历集合
for(int i = 0;i
使用foreach
for(集合元素类型 变量名 : 集合) {
//操作元素变量
}
迭代器遍历
Iterator<集合元素类型> iterator = 集合对象名.iterator();
while(iterator.hasNext()){
集合类型元素 变量名 = iterator.next();
system.iut.println(变量名);
}
void addFirst(E e)//将指定元素插入此列表的开头
void addLast(E e)//将指定元素添加到此列表的结尾
E getFirst()//返回此列表的第一个元素
E getLast()//返回此列表的最后一个元素
E removeFirst()//移除并返回此列表的第一个元素
E removeLast()//移除并返回此列表的最后一个元素
E pop()//从此列表所表示的堆栈处弹出一个元素
void push(E e)//将元素推入此列表所表示的堆栈
foreach、迭代器
无序、唯一、允许null元素、高效性
HashSet存放自定义类对象时元素插入过程:
当向HashSet中插入元素时,先获取元素的hashCode()值,
再检查HashSet中是否存在相同哈希值的元素,
如果元素哈希值唯一,则直接插入元素
如果存在相同哈希值的元素,会调用元素的equals()方法来进一步判断元素是否是相同。如果相同,则不会插入重复元素;如果不同,则插入
所以为了避免出现属性值相同对象的重复插入,需要类中重写equals()方法和hashCode()方法。
这是因为在 Java 中,对象的相等性判断是基于 equals() 方法的,而 hashCode() 方法在集合类中常用于快速查找和存储对象。在使用集合类(如 HashMap、HashSet 等)时,对象作为键或值存储在集合中,它们的相等性判断和查找都依赖于 equals() 和 hashCode() 方法。
所以,为了保证对象的正确比较和查找,在重写 equals() 方法时,必须同时重写 hashCode() 方法。如果两个对象是相等的(即 equals() 方法返回 true),那么它们的 hashCode() 方法应该返回相同的哈希码。
如果你只重写了 equals() 方法而没有重写 hashCode() 方法,那么在集合类中进行查找或比较时可能会出现意外的结果,因为对象的哈希码可能不匹配。因此,为了保持对象在比较和查找时的一致性和正确性,通常我们需要同时重写 equals() 方法和 hashCode() 方法。确保在 equals() 方法返回 true 时,hashCode() 方法返回相同的哈希码。这样就可以确保对象在集合类中的正确性和一致性操作。
有序性(能够自动调整顺序)、唯一性、动态性、高效性
存放自定义对象时由于类对象是不可比较的,会出现ClassCastException异常
因为:TreeSet是一个有序集合,存储数据时,一定要指定元素的排序规则,有两种指定的方式
自然排序(元素所属类型要实现java.lang.Comparable 接口)
public class Test073_Person {
public static void main(String[] args) {
Set set = new TreeSet<>();
set.add(new Person("zs",22));
set.add(new Person("li",25));
set.add(new Person("ww",12));
Iterator it = set.iterator();
while(it.hasNext()){
Person p =it.next();
System.out.println(p);
}
}
}
class Person implements Comparable{
private String name;
private int age;
public Person(){};
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o){
//先按name升序,name相同则按age降序
//this.name已有元素,o.name这次要插入的元素
if(o.name.equals(this.name)){
if(o.age != this.getAge()){
return this.getAge-o.age;
}
}
return this.name.compareTo(o.name);
}
}
compareTo方法说明:(比较字符串)
int result = this.属性.compareTo(o.属性);
result的值大于0,说明this比o大 (升序)
result的值小于0,说明this比o小 (降序)
result的值等于0,说明this和o相等
比较器排序
创建Comparator接口。重写compare()方法
创建TreeSet对象,将比较器对象作为参数传递给构造函数
public class Test073_Comparator {
public static void main(String[] args) {
//适用匿名内部类
Comparator comp = new Comparator(){
//重写比较算法:先按按age升序,age相同则按name降序
@Override
public int compare(Person1 o1,Person1 o2){
if(o1.getAge() != o2.getAge()){
return o1.getAge()-o2.getAge();
}else {
return o2.getName().compareTo(o1.getName());
}
}
};
Set set = new TreeSet<>(comp);
//3.添加元素
set.add(new Person1("zs",21));
set.add(new Person1("ww",20));
set.add(new Person1("zs",21));
set.add(new Person1("tom",19));
set.add(new Person1("tom",23));
set.add(new Person1("jack",20));
for(Person1 p: set){
System.out.println(p);
}
}
}
LinkedHashSet 是HashSet 的一个子类,具有HashSet 的高效性能和唯一性特性,并且保持了元素的插入顺序,其底层基于哈希表和链表实现。
最长用HashMap()
存储元素时,必须以key-value(键值对)的方式进行、键唯一、可重复值、高效查询和访问、
put(K key, V value)把key-value存到当前Map集合中,key存在则会覆盖原来的value值
putAll();把指定map中的所有key-value,存到当前Map集合中
boolean containsKey(Object key)//当前Map集合中是否包含指定的key值
boolean containsValue(Object value)//当前Map集合中是否包含指定的value值
Set keySet()//返回Map集合中所有的key值
Collection values()//返回Map集合中所有的value值
Set> entrySet()//把Map集合中的的key-value封装成Entry类型对象,再存放到set集合中,并返回
V get(Object key) //在当前Map集合中,通过指定的key值,获取对应的value
借助Map中的keySet方法,获取一个Set集合对象,而遍历Set集合获取每一个key值,再根据key获取对应的value。
//1,获取key,根据key获取value
Set set = map.keySet();//Integer为键的类型
for(Integer k : set){
String v = map.get(k);
System.out.println("id:" + k+ "," + "name:" + v);
}
助Map中的entrySet方法,获取一个Set对象,内部包含了Map集合中所有的键值对,然后对键值对进行拆分,得到key和value进行输出。
//获取所有的key-value键值对,得到一个Set集合
Set> entrySet = map.entrySet();
//遍历set集合
for(Map.Entry entry : entrySet){
//拆分键值对中的key和value
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println("id: " + key + " name: " + value);
}
HashMap底层借助哈希表实现,元素的存取顺序不能保证一致。
HashMap存储的键值对时,如果键类型为自定义类,那么一般需要重写键所属类的hashCode()和equals()方法(重要,最常用)。
特点:键唯一、值可重复、无序、线程不安全、键和值允许使用null
结论:key类型如果为自定义类型,重写其hashCode和equals方法!
HashMap中add(key,value)时,需要判断key是否存在(先hashCode再equals)
HashMap中containsKey(key)时,同样要借助hashCode和equals方法
HashMap中remove(key)时,同样要借助hashCode和equals方法
线程安全、键和值都不能为空、哈希表实现
键是按照自然顺序或自定义比较器进行排序的、红黑树实现、键唯一,值可重复、线程不安全、
会根据插入的键值对动态地调整红黑树的大小。
使用自定义比较器规则排序
public class Test086_Comparator {
public static void main(String[] args) {
Comparator comp = new Comparator() {
@Override
public int compare(Student2 o1, Student2 o2) {
//名字降序,姓名一样,则年龄升序
if(!o1.getName().equals(o2.getName())){
return o2.getName().compareTo(o1.getName());
}else {
return o1.getAge()-o2.getAge();
}
}
};
Map map = new TreeMap<>(comp);
map.put(new Student2("zs", 78),"010");
map.put(new Student2("rose", 82),"005");
map.put(new Student2("lucy", 79),"009");
map.put(new Student2("lucy", 79),"009");
map.put(new Student2("tom", 68),"019");
map.put(new Student2("tom", 86),"012");
map.put(new Student2("ww", 67),"002");
Set> entrySet = map.entrySet();
for(Map.Entry entry : entrySet){
System.out.println(entry.getKey()+" : " + entry.getValue());
}
}
}
集合工具类是java.util.Collections ,专门来操作集合对象,里面都是静态方法,可以直接调用。
Collection 是单列集合根接口, Collections 是集合工具类,两者不同!
fill方法,使用指定元素替换指定列表中的所有元素
max方法,根据元素的自然顺序,返回给定集合的最大元素
min方法,根据元素的自然顺序,返回给定集合的最小元素
reverse方法,反转集合中的元素
sort方法,根据元素的自然顺序,对指定列表按升序进行排序
shuffle方法,使用默认随机源对指定列表进行置换,随机打乱
addAll方法,往集合中添加一些元素
六、综合案例
设计实现一个斗地主游戏,该游戏可以生成牌、洗牌、发牌,三名玩家可以看自己手里的牌,最后也能看到三张底牌。
具体要求:
package com.briup.chap08.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Test10_Game {
public static void main(String[] args) {
// 创建一个Map集合,保存牌面点数和权重值的关系
Map weights = new HashMap<> ();
weights.put("3", 1);
weights.put("4", 2);
weights.put("5", 3);
weights.put("6", 4);
weights.put("7", 5);
weights.put("8", 6);
weights.put("9", 7);
weights.put("10", 8);
weights.put("J", 9);
weights.put("Q", 10);
weights.put("K", 11);
weights.put("A", 12);
weights.put("2", 13);
// 所有可用的牌面点数
Set numbers = weights.keySet();
// 所有可用的花色
Color[] colors = Color.values();
// 生成52张扑克牌
List cards = new ArrayList<>();
for (String number : numbers) {
for (Color color : colors) {
cards.add(new Card(number, color,
weights.get(number)));
}
}
// 生成两张王牌
cards.add(new Card("小王", null, 14));
cards.add(new Card("大王", null, 15));
// 洗牌
Collections.shuffle(cards);
// 表示三个玩家手牌的集合
// List player1 = new ArrayList<>();
// List player2 = new ArrayList<>();
// List player3 = new ArrayList<>();
List> players = Arrays.asList(
new ArrayList(),
new ArrayList(),
new ArrayList()
);
// 表示底牌的集合
List holecards = new ArrayList<>();
// 获取牌的总数
int size = cards.size();
// 底牌数量
final int holecardsNum = 3;
// 遍历所有的扑克牌,依次发给每个玩家
for (int i = 0; i < size; i++) {
// 取出一张新牌
Card card = cards.get(i);
// 最后三张牌,存入底牌集合
if (i >= size - holecardsNum) {
holecards.add(card);
continue;
}
int r = i % 3;
players.get(r).add(card);
}
Comparator c = new Comparator() {
@Override
public int compare(Card o1, Card o2) {
// 先根据权重(牌面点数)排序
int w1 = o1.getWeight();
int w2 = o2.getWeight();
if (w1 != w2) {
return w1 - w2;
} else {
return o1.getColor().getWeight()
- o2.getColor().getWeight();
}
}
};
// 完成排序
for (List list: players) {
list.sort(c);
System.out.println(list);
}
// players.forEach(list -> list.sort(c));
holecards.sort(c);
// 输出玩家手牌和底牌
System.out.println(holecards);
}
}
enum Color {
HX("♥", 1), // 红心
HT("♠", 2), // 黑桃
FK("♦", 3), // 方块
CH("♣", 4); // 草花
private String icon;
private int weight;
private Color(String icon, int weight) {
this.icon = icon;
this.weight = weight;
}
public int getWeight() {
return this.weight;
}
@Override
public String toString() {
return this.icon;
}
}
// 扑克牌类
class Card {
// 点数
private final String number;
// 花色
private final Color color;
// 权重
private final int weight;
public Card(String number, Color color, int weight) {
this.number = number;
this.color = color;
this.weight = weight;
}
// 获取花色的方法
public Color getColor() {
return color;
}
// 获取权重的方法
public int getWeight() {
return weight;
}
@Override
public String toString() {
return color == null ? number : color + number;
}
}