9.9、Set集合
Set 一个不包含重复元素的 collection。
实现类:HashSet类、LinkedHashSet类
1)特点:
Set 集合中的元素是无序的(LinkedHashSet除外),Set集合中是不存在下标的概念,所以肯定没有get(下标)
方法,里面所有的元素都是不重复的。如果有重复的元素,如果此 Set 已包含该元素,则该调用不更改 Set 并返回 false
2)常用方法
方法摘要
boolean add(E e)
如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。
boolean addAll(Collection<? extends E> c)
如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。
void clear()
移除此 set 中的所有元素(可选操作)。
boolean contains(Object o)
如果 set 包含指定的元素,则返回 true。
boolean containsAll(Collection<?> c)
如果此 set 包含指定 collection 的所有元素,则返回 true。
boolean equals(Object o)
比较指定对象与此 set 的相等性。
int hashCode()
返回 set 的哈希码值。
boolean isEmpty()
如果 set 不包含元素,则返回 true。
Iterator<E> iterator()
返回在此 set 中的元素上进行迭代的迭代器。
boolean remove(Object o)
如果 set 中存在指定的元素,则将其移除(可选操作)。
boolean removeAll(Collection<?> c)
移除 set 中那些包含在指定 collection 中的元素(可选操作)。
boolean retainAll(Collection<?> c)
仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。
int size()
返回 set 中的元素数(其容量)。
Object[] toArray()
返回一个包含 set 中所有元素的数组。
<T> T[]
toArray(T[] a)
返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。
3)迭代方式
增强 for 循环
迭代器
案例:
在HashSet中存储3个员工,每个员工要保存的信息是员工编号,员工姓名,员工年龄。并演示3种方式进行迭代,输出员工的信息。
在上题中添加一个重复的元素,并进行迭代,输出元素。查看
元素个数。 4个,要重写 equals 方法,就不会加入重复的元素了。
尝试添加null对象,是否可以添加? 可以添加 null 对象
import java.util.Objects;
public class Emp {
private String empId;
private String empName;
private int empAge;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public int getEmpAge() {
return empAge;
}
@Override
public String toString() {
return empId +
", " + empName +
", " + empAge;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Emp emp = (Emp) o;
return empAge == emp.empAge && Objects.equals(empId, emp.empId) && Objects.equals(empName, emp.empName);
}
@Override
public int hashCode() {
return Objects.hash(empId, empName, empAge);
}
public void setEmpAge(int empAge) {
this.empAge = empAge;
}
public Emp(String empId, String empName, int empAge) {
this.empId = empId;
this.empName = empName;
this.empAge = empAge;
}
}
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest02 {
public static void main(String[] args) {
HashSet<Emp> empHashSet = new HashSet<>();
empHashSet.add(new Emp("e001","小黄",20));
empHashSet.add(new Emp("e002","中黄",22));
empHashSet.add(new Emp("e003","大黄",28));
empHashSet.add(new Emp("e003","大黄",28));
//两个emp 地址值不同,集合中会重复打印
//需要重写 Emp 的 equals方法,避免重复打印
//增强 for 循环
for (Emp emp : empHashSet) {
System.out.println(emp);
}
System.out.println("============================");
//迭代器
Iterator<Emp> iterator = empHashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
需求:Scanner接收用户输入一个字符串。“aaabbbccdd”,过滤
重复字符。
import java.util.HashSet;
import java.util.Scanner;
public class test01 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("输入字符串:");
String str = input.next(); //“aaabbbccdd"
char[] chars = str.toCharArray();
HashSet<Character> hashSet = new HashSet<>();
for (char ch : chars) {
hashSet.add(ch);
}
for (Character chh : hashSet) {
System.out.print(chh);
} //abcd
}
}
4)HashSet
关于 Set接口,建议观看韩顺平的B站视频学习
HahSet 原理
LinkedHashSet :
-
LinkedHashSet 是 HashSet 的子类
-
LinkedHashSet 底层是一个 LinkedHashMap ,底层维护了一个 数组+双向链表
-
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
-
LinkedHashSet 无重复元素
5)Set重复过滤的原理
1.如果是自定义对象类型:
对象默认的equals比较的是地址值
如果想不比较地址,比较属性,就重写equals方法
2.如果是String,Integer等(包装类的 equals 方法已经修改过)。
比较内容
9.10、Map 集合
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
1)Map 的特点?什么是双列集合?
1)Map 与 Collection 并列存在。用于保存具有映射关系的数据 :Key – Value
2)Map 中的 key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中
3)Map 中的 key 不允许重复。keySet
4)Map 中的 value 可以重复
5)Map 的 key 可以为 null,value 也可以为null,注意 key 为 null,只能有一个,value 为 null,可以多个
6)key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value
2)Map总结
1.HashMap的扩容机制和底层跟HashSet基本一致,数组+单向链
表,HashMap使用了key和value来保存数据,而HashSet只使用了
key来保存数据。
2.HashMap无序的,只能保存一个null的key,如果key一样,就是
覆盖操作。
3)常用API
void clear()
从此映射中移除所有映射关系(可选操作)。
boolean containsKey(Object key)
如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(Object value)
如果此映射将一个或多个键映射到指定值,则返回 true。
Set<Map.Entry<K,V>> entrySet()
返回此映射中包含的映射关系的 Set 视图。
boolean equals(Object o)
比较指定的对象与此映射是否相等。
V get(Object key)
返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
int hashCode()
返回此映射的哈希码值。
boolean isEmpty()
如果此映射未包含键-值映射关系,则返回 true。
Set<K> keySet()
返回此映射中包含的键的 Set 视图。
V put(K key, V value)
将指定的值与此映射中的指定键关联(可选操作)。
void putAll(Map<? extends K,? extends V> m)
从指定映射中将所有映射关系复制到此映射中(可选操作)。
V remove(Object key)
如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
int size()
返回此映射中的键-值映射关系数。
Collection<V> values()
返回此映射中包含的值的 Collection 视图。
4)HashMap
建议观看韩顺平B站上的视频学习:
HashMap 小结
HashMap 底层机制及源码剖析:
5)HashTable
Hashtable 和 HashMap 对比:
6)循环遍历 Map 方式
遍历方式一:
- 获取 key 的集合 keySet() 方法
- 通过 key 获取 value get(key) 方法
遍历方式二:
- 通过 entrySet() 方法获取 entry 对象,里面就包含了所有的 key 和 value
Set<Map.Entry<k,v>> entrySet()
返回此映射所包含的映射关系的 Set 视图
- 在通过 entry 对象的 getKey() 和 getValue() 来获取数据。
k getKey()
返回与此项对应的键
v getValue()
返回与此项对应的值
public interface Map<K,V> {
//内部接口
interface Entry<K,V> {
K getKey();
V getValue();
}
}
7)练习
需求:Scanner接收用户输入一个字符串。“aaabbbccdd”,
过滤重复字符并统计重复次数。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入一个字符串:");
//aaabbbccdd
String str = input.next();
//1.先把字符串转换为字符数组
char[] chars = str.toCharArray();
//2.创建HashMap集合
HashMap<Character, Integer> map = new HashMap<>();
//key - 字符 value - 次数
for (char ch : chars) {
//定义一个变量:保存次数
int count = 1;
//如果key存在
if(map.containsKey(ch)){
//2-1: 先从a中获取次数
count = map.get(ch);
//2-2:然后在基础上+1
count++;
}
//2-3:把次数重新放入集合中
map.put(ch,count);
}
//遍历
Set<Character> keySet = map.keySet();
for (Character key : keySet) {
System.out.println(key + ":" + map.get(key));
}
}
9.11、嵌套组合
集合中放入集合:
如:
List<Map<String,对象类型>> list = new ArrayList();
Map<Integer,Map<String,对象类型>> map2 = new HashMap<>();
案例:
public class Student {
private String name;
private int age;
private double score;
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
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;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
public class TestStu {
public static void main(String[] args) {
Map<String, Student> map = new HashMap<>();
map.put("A001",new Student("小强",21,39.5));
map.put("A002",new Student("赵四",22,59.5));
map.put("A003",new Student("张三",21,69.5));
System.out.println("学号/t/t姓名/t/t年龄/t/t成绩");
//遍历集合
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()){
String stuId = iterator.next();
Student student = map.get(stuId);
System.out.println(stuId+"/t/t"+student.getName()+"/t/t"+student.getAge()+"/t/t"+student.getScore());
}
//嵌套集合
List<Map<String,Student>> list = new ArrayList<>();
Map<Integer,Map<String,Student>> map2 = new HashMap<>();
}
}
9.12、Collections工具类的基本应用
作用:是集合的工具类,方便集合的操作。
常用的方法:
1)排序:根据元素的自然顺序 对指定列表按升序进行排序。
void sort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序。
@Test
public void test01(){
//根据元素的自然顺序 对指定列表按升序进行排序。
List<Integer> list = Arrays.asList(34,56,14,68,45,89);
Collections.sort(list);
System.out.println("list = " + list);
}
排序方式扩展:= 了解
需求:想对对象中的属性进行排序???
实现步骤:
1)实现 Comparable 接口
2)实现compareTo()方法
比较的规则:比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
如果满足该规则,升序排序。
如果规则相反,降序 排序。
此对象:当前创建的对象 : this
指定对象:传入的对象Object o
int compareTo(T o)
比较此对象与指定对象的顺序。
注意:因为String类默认重写了compareTo方法,所有可以直接比较。(比较的规律不确定)
案例:
需求:
在集合中存储学生对象,然后对学生的年龄进行升序排序。
如果年龄相同的情况下,想对分数进行升序排序。
如果年龄相同的情况下,想对姓名进行升序排序。
o: 传入的对象
this: 当前对象
规则:当前对象和传入的对象的age属性进行相减对比,
分别返回负数,零,正数。
升序排序
总结:
当前对象.属性 – 传入的对象.属性 – 升序
传入的对象.属性 – 当前对象.属性 – 降序
字符串的比较:直接调用compareTo方法
@Test
public void test02(){
List<Student> list = Arrays.asList(
new Student("柳岩",21,39.5),
new Student("张三",22,59.5),
new Student("李四",22,25.5),
new Student("周富强",19,89.5),
new Student("徐志胜",22,78.5)
);
/**
* 需求:
* 在集合中存储学生对象,然后对学生的年龄进行升序排序。
* 如果年龄相同的情况下,想对分数进行升序排序。
* 如果年龄相同的情况下,想对姓名进行升序排序。
*/
//排序
Collections.sort(list);
System.out.println(list);
}
public class Student implements Comparable<Student>{
private String name;
private int age;
private double score;
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
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;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '/'' +
", age=" + age +
", score=" + score +
"}/n";
}
//如果要实现对象的比较,那么必须实现compareTo方法
/*
o: 传入的对象
this: 当前对象
规则:当前对象和传入的对象的age属性进行相减对比,分别返回负数,零,正数。
升序排序
总结:
当前对象.属性 - 传入的对象.属性 - 升序
传入的对象.属性 - 当前对象.属性 - 降序
*/
@Override
public int compareTo(Student o) {
/* if(this.getAge() - o.getAge() < 0){
return -1;
}else if(this.getScore() - o.getScore() > 0){
return 1;
}
return 0;*/
//优化
/* return (this.getAge() - o.getAge())==0?
(int)(this.getScore()-o.getScore()):(this.getAge() - o.getAge());*/
//满足年龄的情况下,对字符串排序
return (o.getAge() - this.getAge())==0?
(this.getName().compareTo(o.getName())):(o.getAge() - this.getAge());
//如果一定要按中文比较
//Comparator<Object> comparator = Collator.getInstance(Locale.CHINA);
//return (o.getAge() - this.getAge()) == 0 ?
//(comparator.compare(o.getName(),this.getName())) : (o.getAge() - this.getAge())
}
}
2)2分查找法
static <T> int binarySearch(List list, T key) 使用二分搜索法搜索指定列表,以获得指定对象。
3)反转集合元素
static void reverse(List<?> list) 反转指定列表中元素的顺序。
4)替换所有元素
static <T> void fill(List<? super T> list, T obj) 3 使用指定元素替换指定列表中的所有元素。
5)随机置换元素位置:洗牌
static void shuffle(List<?> list) 使用默认随机源对指定列表进行置换。
9.13、如何选择集合实现类:
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/280247.html