一、
底层结构: 双向链表
特点:
增删效率较高
根据索引查询,遍历,修改效率低
应用场景: 在大量做增删,少量做查询的位置适合使用LinkedList
新增: 新增了一些操作链表头尾的方法
public static void main(String[] args) { LinkedList<String> linked = new LinkedList<>(); System.out.println(linked); 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()); }
②TreeSet
默认升序,去重
红黑树
当方法|构造器参数为接口类型的时候,实参可以考虑是否可以通过一个Lambda表达式进行传递
lambda可以让行为作为参数|数据传递,配合函数式接口,可以让定义与实现变的更加简单灵活
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(); } }
练习:
定义一个User类型的数组,使用Arrays.sort方法对这个数据做升序排序
排序规则: 要求按照用户编号降序排序
排序规则: 要求按照用户员工的余额升序排序
分别打印
static void sort(Object[] a) 根据元素的natural ordering ,将指定的对象数组按升序排序。
static void sort(T[] a, Comparator<? super T> c) 根据指定比较器引发的顺序对指定的对象数组进行排序。
先写一个Person类
public class Person { 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 void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
public class SetDemo02 { public static void main(String[] args) { Person[] ps = { new Person("黄磊",22), new Person("冯顺",22), new Person("汪健",18), new Person("程旭",21), }; System.out.println(Arrays.toString(ps)); ///升序排序 Arrays.sort(ps); //使用默认的比较规则,数据Person类型的内部比较器 System.out.println(Arrays.toString(ps)); //根据姓名做升序排序 //Arrays.sort(ps,new AAA()); /*Arrays.sort(ps, new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return o2.getName().compareTo(o1.getName()); } });*/ //lambda Arrays.sort(ps, (Person o1, Person o2) ->{ return o2.getName().compareTo(o1.getName()); }); //lambda 简化 Arrays.sort(ps, (o1, o2) ->o2.getName().compareTo(o1.getName())); System.out.println(Arrays.toString(ps)); } } //外部比较器规则 class AAA implements Comparator<Person>{ @Override public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }
底层结构: 哈希表(数组+链表+红黑树)
特点:
做查询,增删效率较高
无序去重
初始容量: 16
加载因子: 0.75 ->扩容的临界点
扩容的临界点 = 容量加载因子;
12 = 160.75; 当存储的数据到12就扩容
HashSet 与 TreeSet之间的选择
如果想要数据存储的时候默认升序|降序->TreeSet
否则建议选择HashSet
构建一个HashSet 存储字符串类型的数据,做基本操作行为,然后遍历
构建一个HashSet 存储自定义引用数据类型的数据,做基本操作行为,然后遍历
通过HashSet存储自定义引用数据类型的数据去重问题:
需要在自定义引用数据类型中,重写hashcode与equals方法,根据内容计算比较
hashcode 与 equals :
equals相等hashcode值肯定相等
hashcode相等,equals不一定相等
public class HashSet03 { public static void main(String[] args) { HashSet<Person> hash = new HashSet<>(); //默认根据地址做去重 hash.add(new Person("",18)); hash.add(new Person("",18)); System.out.println(hash); System.out.println(new Person("",18).hashCode()); System.out.println(new Person("",18).hashCode()); HashSet set1=new HashSet(hash); } }
接口
存储键值对的数据
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 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()); } }
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方法
public class HashMapDemo02 { public static void main(String[] args) { Map<User,String> hash = new HashMap<>(); hash.put(new User("zhangsan",123),"张三"); hash.put(new User("lisi",123),"lisi"); hash.put(new User("王五",123),"王五"); hash.put(new User("zhangsan",123),"张三"); System.out.println(hash); } }