一.Set 接口
1.基本概念
Set : 是 Collection 的子接口, 特点是无序不可重复(自动去重),
新增方法: Set< E > of(E... elements)返回包含任意数量元素的不可修改集合。 无序: 存放的顺序与内部真实存储的顺序不一致(内部有自己存储的规则). 去重: 两个数据调用equals方法返回值true,相同需要去重,false不同可以添加.
遍历方式只有两种 :1.for each 2.迭代器 iterator
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Set {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(123);//自动去重只能存进去一个
set.add(123);
System.out.println(set);//[123]
Set<String> set2 = new HashSet<>();
set2.add("哈哈");
set2.add("ab");
set2.add("呵呵");
set2.add("bd");
set2.add("a");
set2.add("吼吼");
System.out.println(set2);//[ab, a, bd, 哈哈, 呵呵, 吼吼]真实的存储顺序与实际存入顺序不同, 按照集合内部自己的排序方式.
//for each遍历
int i= 1;
for (Object obj:set2) {
if(i==set2.size()){
System.out.print(obj);
break;
}
System.out.print(obj+" ");
i++;
}
//迭代器遍历
Iterator it = set2.iterator();
while (it.hasNext()){
System.out.print(it.next()+" ");
}
//static <E> Set<E> of(E... elements) 返回包含任意数量元素的不可修改集。
Set<Integer> set3 = Set.of(1,2,3,4,5);
}
}
2.HashSet实现类
HashSet : Set 接口的实现类.无新增功能,无序不可重复. 底层结构: 哈希表 (数组+链表+红黑树) ->是由HashMap维护. 优点 : 查询,增删效率较高. 应用场景: 实现不存储相同数据,查询,增删效率较高的时候建议使用HashSet
哈希表 : 数组+链表+红黑树
存储数据的步骤:
-
数据首先传给 hashcode ( ) 方法, hashcode 方法默认根据对象的地址通过hash指定的算法计算后返回一个int类型的整数.
-
得到返回的int整数后,通过指定的hash算法计算数据要存在数组的哪个索引位置,不同的jdk版本哈希算法不尽相同,一般会尽量分散在数组的每个索引位置.
-
确定索引位置后,如果在指定的索引位置中没有链表及节点存在,直接把这个数据作为链表头存入这个索引位置, 如果已经有链表存在, 就需要遍历这个链表的每一个节点,调用 equals 方法比较这个数据与链表中的节点数据是否相等,如果每一个都不相等就把这个数据存入这个链表的最后.
-
当链表长度>8并且数组的总长度>64的时候,会把链表变为红黑树.
注意: 前提是重写hashcode与equals方法,让它根据成员变量值去计算而不是对象地址.equals相等,hashcode的结果一定相等; hashcode结果一样, equals 不一定相等.
import java.util.HashSet;
import java.util.Objects;
public class HashSet {
public static void main(String[] args) {
HashSet<Person> hash = new HashSet();
hash.add(new Person("天一","男",18));
hash.add(new Person("天二","男",23));
hash.add(new Person("天三","男",19));
hash.add(new Person("天四","男",24));
hash.add(new Person("天五","男",25));
hash.add(new Person("天五","男",25));
//两个天五只能存进去一个
for (Person p:hash) {
System.out.println(p);
}
}
}
//自定义类引用数据类型
class Person{
private String name;
private String gender;
private int age ;
public Person() {
}
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name) &&
Objects.equals(gender, person.gender);
}
@Override
public int hashCode() {
return Objects.hash(name, gender, age);
}
}
3. TreeSet 实现类
TreeSet : Set接口的实现类,无序不可重复.
3.1基本定义
底层结构: 红黑树(平衡二叉树). 特点: 自动做生序排序. 新增功能: 新增了一些能够比较的相关功能.
public class TreeSet {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>();
set.add(5);
set.add(2);
set.add(1);
set.add(3);
set.add(4);
System.out.println(set);[1,2,3,4,5]
//E ceiling(E e) 返回此set中大于或等于给定元素的 null元素,如果没有这样的元素,则 null 。
System.out.println(set.ceiling(6));//没有大于6的,null
//E first() 返回此集合中当前的第一个(最低)元素。
System.out.println(set.first());
//E last() 返回此集合中当前的最后一个(最高)元素。
System.out.println(set.last());
//E higher(E e) 返回此集合中的最小元素严格大于给定元素,如果没有这样的元素,则 null 。
System.out.println(set.higher(1));//从第一个开始比较拿出第一个比1大的值.
//E pollFirst() 检索并删除第一个(最低)元素,如果此组为空,则返回 null 。
//E pollLast() 检索并删除最后一个(最高)元素,如果此集合为空,则返回 null 。
System.out.println(set.pollFirst());//删除第一个数
System.out.println(set.pollLast);//删除最后一个数
}
}
3.2 比较器(比较规则)
在 TreeSet 存储自定义引用数据类型的数据时, 存储对象的排序与去重都需要指定比较规则.
按编写位置分为:内部比较器和外部比较器.在没有指明使用外部比较器(定制排序)的情况下,默认使用内部比较器(自然排序).
-
内部比较器 | 自然排序 :定义在需要存储的引用数据类型的类内部的一个指定的比较方式(方法).缺点是代码固定不够灵活.
步骤:1)让引用数据类型的类实现 Comparable 接口, 2)重写 Comparable 的 compareTo ( T o )方法,返回值为 int 类型. T1.compare( T2 ) .比较两个数据的大小, 当返回值为 0 时->T1 = T2 , 返回正数时-> T1 > T2 .返回负数时-> T1 < T2 .
-
外部比较器 | 定制排序 : 定义在要存储的引用数据类型的类外部的一个指定的比较规则(方法).
步骤:1)让引用数据类型的类实现 Comparator 接口, 重写 compare ( T t1, T t2)方法返回值为 int 类型. t1.compare( t2 ) .比较两个数据的大小, 当返回值为 0 时->t1 = t2 , 返回正数时-> t1 > t2 .返回负数时-> t1 < t2 .
import java.util.Arrays;
import java.util.Comparator;
public class TreeSet {
public static void main(String[] args) {
//指明外部比较器
//com 可简化为lambda表达式 (x,y)->x.getAge()-y.getAge()
TreeSet<User> treeSet = new TreeSet<>(com);
treeSet.add(new User("孙悟空","男",9999));
treeSet.add(new User("盖伦","男",30));
treeSet.add(new User("彦","女",6500));
treeSet.add(new User("赵信","男",32));
treeSet.add(new User("炙心","女",4300));
treeSet.add(new User("卡尔","男",9999));
//匿名内部类
Comparator<User> com = new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
if(o1.getGender().compareTo(o2.getGender())==0){
return o1.getAge()-o2.getAge();
}
return o1.getGender().compareTo(o2.getGender());
}
};
for (User u:users) {
System.out.println(u);
}
}
}
//数据类型的类实现Comparable接口,<User>表示只能比较这个类型的对象数据
public class User implements Comparable<User>{
private String name;
private String gender;
private int age ;
public User() {
}
public User(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age &&
Objects.equals(name, user.name) &&
Objects.equals(gender, user.gender);
}
@Override
public int hashCode() {
return Objects.hash(name, gender, age);
}
//重写compareTo(T o)方法.内部比较器
@Override
public int compareTo(User o) {
if(this.getName().compareTo(o.getName())==0){
if(this.getAge()-o.getAge()==0){
this.getGender().compareTo(o.getGender());
}else {
return this.getAge()-o.getAge();
}
}
return this.getName().compareTo(o.getName());
}
}
二.Map<K,V>接口
1.基本定义
Map<K,V> : 集合中的元素由键值对k-v组成, Map的无序与去重 由key决定 k: 可以为任意引用数据类型数据 --> Set 无序不可重复 v: 可以为任意引用数据类型数据 --> Collection 可重复无序 一个key只能对应一个value->映射关系, 可以根据key操作value
import java.util.HashMap;
import java.util.Map;
public class Map {
public static void main(String[] args) {
//创建Map集合,key存储int类型数据,value储存String类型数据
Map<Integer,String> map = new HashMap<>();
//V put(K key, V value) 将指定的值与此映射中的指定键相关联。
map.put(1001,"张三");//成对储存
map.put(1002,"李四");
map.put(1003,"王五");
System.out.println(map.put(1002,"LISA"));//重复的key,value值会被覆盖,返回被覆盖的值
System.out.println(map);
//V get(Object key) 返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。
System.out.println(map.get(1001));
//boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。
//boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。
System.out.println(map.containsKey(1003));
System.out.println(map.containsValue("zhangsan"));
//V remove(Object key) 如果存在,则从该映射中移除键的映射。
System.out.println(map.remove(1001));
System.out.println(map);
}
}
2.遍历方式
1.keySet 获取所有的key值,返回一个set集合.既可以获取到key,也可以获取到value. 2.values() 获取map集合中所有键值对的value,返回一个Collection集合.只能获取到value, 3.entrySet() 获取所有的键值对->Map.Entry 类型->表示一个键值对.
import java.util.*;
public class Each {
public static void main(String[] args) {
//创建Map集合
Map<Integer,String> map = new HashMap<>();
map.put(1000,"天");
map.put(1001,"地");
map.put(1002,"人");
//1.keySet
Set<Integer> keys = map.keySet();
for (Integer i :keys){
System.out.println(i+"<-->"+map.get(i));
}
//2.values
Collection<String> val = map.values();
for(String s:val){
System.out.println(s);
}
//3.entrySet
Set<Map.Entry<Integer,String>> set = map.entrySet();
Iterator<Map.Entry<Integer,String>> it = set.iterator();
for(;it.hasNext();){
Map.Entry entry = it.next();
System.out.println(entry.getKey()+"<-->"+entry.getValue());
}
}
}
3.HashMap实现类
底层结构: 哈希表(数组+链表+红黑树).特点: 查询,增删效率较高.
扩容问题: 初始容量16,newCap = oldCap << 1 数组每次扩容原容量的两倍 DEFAULT_INITIAL_CAPACITY 初始容量 16 DEFAULT_LOAD_FACTOR : 默认加载因子 0.75 threshold : 扩容临界值 DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY
在使用HashMap存储自定义的引用数类型的数据时, 类型中应该重写hashcode方法(作为比较规则)实现去重和value的覆盖.
import java.util.Set;
import java.util.TreeMap;
public class HashMap {
public static void main(String[] args) {
HashMap<Teachers,String> hmap = new HashMap<>();
hmap.put(new Teachers("殷老师","java初级"),"5年");//被覆盖
hmap.put(new Teachers("李老师","大数据"),"6年");
hmap.put(new Teachers("裴老师","java高级"),"7年");
hmap.put(new Teachers("廖老师","java中级"),"8年");
hmap.put(new Teachers("卢老师","java鼓励师"),"9年");
hmap.put(new Teachers("殷老师","董事长"),"2年");
Set<Teachers> set = hmap.keySet();
for(Teachers s:set){
System.out.println(s+"<-->"+hmap.get(s));
}
}
}
4.TreeMap实现类
TreeSet底层是由TreeMap维护的,TreeMap 新增了一些有关于比较的方法. 底层结构: 红黑树. 特点: 自动做升序排序(根据key做升序)(key为自定义引用数据类型时需要比较器).
import java.util.Set;
import java.util.TreeMap;
public class TreeMap {
public static void main(String[] args) {
TreeMap<Teachers,String> tmap = new TreeMap<>((t1,t2)->t1.getName().compareTo(t2.getName()));
tmap.put(new Teachers("殷老师","java初级"),"5年");
tmap.put(new Teachers("李老师","大数据"),"6年");
tmap.put(new Teachers("裴老师","java高级"),"7年");
tmap.put(new Teachers("廖老师","java中级"),"8年");
tmap.put(new Teachers("卢老师","java鼓励师"),"9年");
tmap.put(new Teachers("殷老师","董事长"),"2年");
Set<Teachers> set = tmap.keySet();
for(Teachers s:set){
System.out.println(s+"<-->"+tmap.get(s));
}
}
}
5.Properties 类
Properties : 存储字符串类型的键值对,特点是可以保存到流中或从流中加载。
优点 : 可以通过Properties实现软编码,从满足Properties特点的配置文件中读取数据,便于后期维护.
使用步骤: 1.定义一个(后缀名为.properties的)配置文件 xx.properties (键值对都是字符串), 在文件中保存键值对.(如: 张三=河南人) 2.创建Properties类型的对象,调用load从流中加载(输入流的数据源就是配置文件). 3.从配置文件中读取数据,加载使用.
import java.io.IOException;
import java.util.Properties;
public class Properties {
public static void main(String[] args) throws IOException {
Properties pro = new Properties();
//void load(InputStream inStream) 从输入字节流中读取属性列表(键和元素对)。
pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
System.out.println(pro.getProperty("username"));//zhangsan
System.out.println(pro.getProperty("password"));//root
}
}
db.properties : 配置文件
username=zhangsan
password=root