Hashset
HashSet 无序,去重
底层结构: 哈希表(数组+链表+红黑树)
特点:
做查询,增删效率较高
无序去重
初始容量: 16
加载因子: 0.75 ->扩容的临界点
扩容的临界点 = 容量加载因子;
12 = 160.75; 当存储的数据到12就扩容
HashSet 与 TreeSet之间的选择
如果想要数据存储的时候默认升序|降序->TreeSet
否则建议选择HashSet
构建一个HashSet 存储字符串类型的数据,做基本操作行为,然后遍历
构建一个HashSet 存储自定义引用数据类型的数据,做基本操作行为,然后遍历
TreeSet
TreeSet
默认升序,去重
红黑树
当方法|构造器参数为接口类型的时候,实参可以考虑是否可以通过一个Lambda表达式进行传递
lambda可以让行为作为参数|数据传递,配合函数式接口,可以让定义与实现变的更加简单灵活
Arrays工具类 操作数组的工具类
练习:
定义一个User类型的数组,使用Arrays.sort方法对这个数据做升序排序
排序规则: 要求按照用户编号降序排序
排序规则: 要求按照用户员工的余额升序排序
分别打印
static void sort 根据元素的natural ordering ,将指定的对象数组按升序排序。
static void sort 根据指定比较器引发的顺序对指定的对象数组进行排序。
public class SetDemo01 {
public static void main(String[] args) {
//匿名内部类 简化实现类IMPL
Comparator<Person> com = new Comparator<Person>(){
@Override
public int compare(Person o1, Person o2) {
return o2.getAge() - o1.getAge();
}
};
//Lambda
com = (Person o1, Person o2)->{
return o1.getAge() - o2.getAge();
};
//指定使用外部比较规则
//TreeSet<Person> tree= new TreeSet<Person>(com);
TreeSet<Person> tree= new TreeSet<Person>((Person o1, Person o2)->{
return o1.getAge() - o2.getAge();
});
tree.add(new Person("胡歌",35));
tree.add(new Person("大表哥",30));
tree.add(new Person("金城武",34));
tree.add(new Person("谢霆锋",30));
System.out.println(tree);
}
}
//外部比较器
class Impl implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
}
LinkedList
LinkedList 有序可重复
底层结构: 双向链表
特点:
增删效率较高
根据索引查询,遍历,修改效率低
应用场景: 在大量做增删,少量做查询的位置适合使用LinkedList
新增: 新增了一些操作链表头尾的方法
练习: 使用LinkedList存储自定义引用数据类型的数据,并操作练习
public class ListDemo01 {
public static void main(String[] args) {
LinkedList<String> linked = new LinkedList<>();
linked.add("haha");
linked.add("hehe");
linked.add("heihei");
linked.add("houhou");
linked.add("xixi");
//新增方法
//void addFirst(E e) 在此列表的开头插入指定的元素。
//void addLast(E e) 将指定的元素追加到此列表的末尾。
System.out.println(linked);
linked.addFirst("first");
linked.addLast("last");
System.out.println(linked);
//E element() 检索但不删除此列表的头部(第一个元素)。
System.out.println(linked.element());
}
}
/*
手写LinkedList
使用单向链表实现
思考实现:
根据索引修改,查询
*/
public class MyLinkedListDemo02 {
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
//list.add("数据");
System.out.println(list.size());
//list.add("haha");
System.out.println(list.size());
System.out.println(list);
}
}
//自定义容器类型: MyLinkedList
class MyLinkedList{
//链表头节点
private Node head;
//长度
private int size;
public MyLinkedList() {
}
/*
添加
*/
public void add(Object value) {
//创建新节点
Node node = new Node(value,null);
//判断是不否存在链表头节点
if(head==null && size==0){
head = node; //新节点就是链表头节点
}else{
//存在原链表,遍历原链表,找到最后一个节点,新节点的地址记录
Node temp = head; //temp指向链表头节点,后面使用temp操作遍历指向每一个节点,直到最后一个
while(temp.getNext()!=null){
temp = temp.getNext();
}
temp.setNext(node); //把新节点挂在原链表的最后
}
size++;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
//1.临时变量,指向链表中的每一个节点
Node temp = head;
//获取每一个节点的值value
while(true){
//结束条件
if(temp==null){
break;
}
sb.append(temp.getValue()); //数据的拼接
sb.append(","); //数据的拼接
temp = temp.getNext(); //指向新节点
}
//StringBuilder replace(int start, int end, String str) 使用指定的 String的字符替换此序列的子字符串中的字符。
if(sb.length()==1){
sb.append("]");
}else{
sb.replace(sb.length()-1,sb.length(),"]");
}
//拼接成字符串返回
return sb.toString();
}
public int size(){
return this.size;
}
}
//节点
class Node{
private Object value; //数据
private Node next; //下一个节点对象的地址
public Node() {
}
public Node(Object value, Node next) {
this.value = value;
this.next = next;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
", next=" + next +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
return Objects.equals(value, node.value) &&
Objects.equals(next, node.next);
}
}
HashMap
HashMap
HashSet --> HashMap
底层结构:
哈希表(数组+链表+红黑树)
特点:
存储键值对类型数据
无序,根据key做去重
查询,修改,删除,增加效率较高
Hash表存储原理:
哈希表: Node节点数组,存储节点数据 节点:key,value,hash,next
1.put(key,value)存储键值对类型的数据
根据key计算hash值,确定桶的位置
2.找到Node数组中的指定索引位置,判断当前位置中是否存在数据,没有存在直接构建一个Node节点对象 new Node(key,value,hash,null),放入数组
如果已经存在值,就比较每一个Node的key与我当前要存储的key是否相等,相等value覆盖,不相等继续判断,最后数据放入链表的最后
默认初始容量: 1<<4 16-> 数组长度
加载因子 : 0.75
最大容量… 1<<30
扩容: 新数组的容量为原容量的2倍 newCap = oldCap << 1
当添加的数据个数>=原数组长度*0.75的时候,就扩容,扩容的是数组的大小
HashMap存储key如果为自定义引用数据类型:
key去重的问题 : key类型中要求重写hashcode与equals方法
Map<K,V>
接口
存储键值对的数据
k-v 一个映射关系
key->value
key与value可以为任意类型的一个数据
一个key只能对应一个value
key是唯一的,无序的 --> Set集合
value是无序可重复的 --> Collection 无序可重复
遍历方式:
Set keySet() 返回所有的key,通过key获取value
Collection values() 获取集合中的所有value值,无法获取key
Set<Map.Entry<K,V>> entrySet()
public class MapDemo01 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
//V put(K key, V value) 添加一个键值对数据,如果key重复,value会覆盖,返回被覆盖的value值,如果key不重复,返回null
System.out.println(map.put(101,"张三"));
System.out.println(map.put(103,"wangwu"));
System.out.println(map.put(102,"lisi"));
System.out.println(map.put(101,"zhangsan"));
System.out.println(map.put(104,"zhangsan"));
System.out.println(map);
//V get(Object key) 根据key获取value,没有返回null
System.out.println(map.get(108));
//int size()
System.out.println(map.size());
//boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。
//boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。
System.out.println(map.containsKey(101));
System.out.println(map.containsValue("zhangsan"));
//V remove(Object key) 如果存在,则从该映射中移除键的映射(可选操作)。
System.out.println(map.remove(102));
System.out.println(map);
//default V replace(K key, V value) 仅当指定键当前映射到某个值时,才替换该条目的条目。
System.out.println(map.replace(101,"zhangsanfeng"));
System.out.println(map);
//default boolean replace(K key, V oldValue, V newValue) 仅当前映射到指定值时,才替换指定键的条目。
System.out.println(map.replace(101,"zhangsan","hahaha"));
System.out.println(map);
//遍历
System.out.println("-------- Set<K> keySet() 返回所有的key,通过key获取value-------------");
Set<Integer> set = map.keySet();
//1)foreach 2)iterator
for(Integer t:set){
System.out.println(t+"-->"+map.get(t));
}
System.out.println("-------------Collection<V> values() 获取集合中的所有value值,无法获取key------");
Collection<String> col = map.values();
//1)foreach 2)iterator
Iterator<String> it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
System.out.println("------- Set<Map.Entry<K,V>> entrySet() ------------");
Set<Map.Entry<Integer,String>> entrys = map.entrySet();
for(Map.Entry<Integer,String> entry:entrys){
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
}
}
public class MapDemo02 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
System.out.println(map.put(100,"张三"));
System.out.println(map.put(102,"李四"));
System.out.println(map.put(103,"王五"));
System.out.println(map.put(104,"赵六"));
System.out.println(map.put(105,"田七"));
System.out.println(map.put(106,"勾八"));
System.out.println(map);
System.out.println(map.get(100));
System.out.println(map.size());
//boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。
//boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。
System.out.println(map.containsKey(105));
System.out.println(map.containsValue("勾八"));
//default boolean replace(K key, V oldValue, V newValue) 仅当前映射到指定值时,才替换指定键的条目。
System.out.println(map.replace(103,"王五","牛逼"));
System.out.println(map);
//遍历
System.out.println("-------- Set<K> keySet() 返回所有的key,通过key获取value-------------");
Set<Integer> set = map.keySet();
for (Integer i:set) {
System.out.println(i+"-->"+map.get(i));
}
System.out.println("-------------Collection<V> values() 获取集合中的所有value值,无法获取key------");
Collection<String> col = map.values();
Iterator<String> it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
System.out.println("------- Set<Map.Entry<K,V>> entrySet() ------------");
Set<Map.Entry<Integer,String>> entrys = map.entrySet();
for (Map.Entry<Integer,String> entry:entrys) {
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
}
}