目录
Map集合概述和特点
1、Map接口概述:
public interface Map<k, V>,将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。此接口取代了Dictionary类,后者完全是一个抽象类,而不是一个接口。
参数类型:K -此映射所维护的键的类型。 V - 映射值的类型。
java.util包下,使用需要导包。 集合所有接口和类都是在util包下。接口方法均抽象,不能被实例化。
2、Map接口和Collection接口的区别:
Map是双列的,Collection是单列的。Map是双列集合的根接口,Collection是单列集合的根接口。
Map的键是唯一的,Collection的子体系Set也是唯一的。
他们的体系是非常一样的。
Map集合的数据结构值针对键有效(HashMap,键是哈希算法;TreeMap,键是二叉树算法),跟值无关;Collection集合的数据结构是针对元素有效。单列集合底层依赖双列集合,HashSet底层使用的Map,HashSet底层源码:
private static final Object PRESENT = new Object(); //直接创建一个Object对象放在值的位置,但是值的位置不显示,都隐藏掉。这样的好处是,二者都依赖哈希算法,只弄一套就行。双列隐藏一列很简单,但单列变成双列,太难了。 public boolean add(E e) { return map.put(e, PRESENT)==null; }
3、Map集合的功能概述
ⅰ.添加功能:
V put(K key, V value):添加元素,将指定的值与该映射中的指定键相关联(可选操作)。返回值类型与Map接口泛型中值的类型相同。 泛型中使用包装类,不能用基本数据类型。
如果键是第一次存储,就直接存储元素,返回null(其实null被覆盖了)。
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值。
ⅱ.删除功能:
void clear():移除所有的键值对元素。
V remove(Object key):根据键删除键值对元素,并把值返回。传键删值。
ⅲ.判断功能:
boolean containsKey(Object key):判断集合是否包含指定的键。
boolean containsValue(Object value):判断集合是否包含指定的值。
boolean isEmpty():判断集合是否为空。
ⅳ.获取功能:
Set<Map.Entry<K, V>> entrySet():拿到所有的键值对象。返回是一个Set,里面写Map.Entry<K, V>。
V get(Object key):根据键获取值。有键无值,返回null。
Set<K> keySet():获取集合中所有键的集合。返回值是Set,Set集合里有Iterator()。
Collection<V> values():获取集合中所有值的集合。参数V与值的类型相同。
ⅴ.长度功能:
int size():返回集合中的键值对的个数。一对代表一个元素。
接口Map.Entry<K, V>概述:public static interface Map.Entry<K, V>,映射项(键—值对)。正在封闭的接口:Map<K, V>。解释:Entry<K, V>是Map<K, V>的内部接口。
接口Map.Entry<K, V>方法:
K getKey() 返回与此项对应的键。
V getValue() 返回与此项对应的值。
4、Map集合的遍历之键找值(Map集合的第一种迭代):
通过查看Map集合的api发现没有Iterator方法。
键找值思路:应用keySet()获取所有键的集合。遍历键的集合,获取到每一个键。根据键应用get(Object key)找值。
案例演示:Map集合的遍历之键找值
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo2_Iterator {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("赵六", 26);
/*Integer i = map.get("张三"); //根据键获取值
System.out.println(i);*/
//迭代器遍历
/*Set<String> keySet = map.keySet(); //获取所有键的集合
Iterator<String> it = keySet.iterator(); //获取迭代器
while(it.hasNext()) { //判断集合中是否有元素
String key = it.next(); //获取每一个键
Integer value = map.get(key); //根据键获取值
System.out.println(key + "=" + value); //打印键值对
}*/
//增强for循环遍历
for(String key : map.keySet()) { //map.keySet()是所有键的集合
System.out.println(key + "=" + map.get(key));
}
}
}
5、Map集合的遍历之键值对对象 找键和值(Map集合的第二种迭代。比第一种迭代提高效率,节约时间)。
键值对对象 找键和值思路:
应用entrySet()把双列集合的键值对变成单列集合的键值对对象,然后遍历这个单列集合获取每一个键值对对象。根据键值对对象获取键和值。
案例演示:Map集合的遍历之键值对对象找键和值。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Demo3_Iterator {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("赵六", 26);
//迭代器遍历
/*Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); //Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并存储在Set集合中。即Map中的一对元素变成了Set集合中的一个对象元素。
Iterator<Map.Entry<String, Integer>> it = entrySet.iterator(); //获取每一个对象。Set集合中存储的每一个Entry对象,所以迭代器与集合泛型一致。
while(it.hasNext()) {
Map.Entry<String, Integer> entry = it.next(); //获取每一个Entry对象。父类引用指向子类对象。
// Entry<String, Integer> entry = it.next(); //直接获取的是子类对象
String key = entry.getKey(); //根据键值对对象获取键
Integer value = entry.getValue(); //根据键值对对象获取值
System.out.println(key + "=" + value);
// System.out.println(entry.getKey() + "=" + entry.getValue());
}*/
//增强for循环遍历
for (Entry<String, Integer> entry : map.entrySet()) { //Map.Entry<String, Integer>没加Map.也可以。Entry是Map.Entry的子类对象,Entry对象代表的是键值对对象,通过Entry对象获取键和值。
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
HashMap
1、案例演示:HashMap集合 键是Student 值是String的案例。双列集合存储自定义对象,保证键的唯一。
/**
* 案例演示:HashMap集合 键是Student 值是String的案例。
* 分析:键是学生对象,代表每一个学生。值是字符串对象,代表学生归属地。
*/
public class Demo5_HashMap {
public static void main(String[] args) {
HashMap<Student, String> hm = new HashMap<>();
hm.put(new Student("张三", 23), "北京");
hm.put(new Student("张三", 23), "上海");
hm.put(new Student("李四", 24), "广州");
hm.put(new Student("王五", 25), "深圳");
System.out.println(hm);
}
}
//HashMap的父类AbstractMap<K,V>重写了toString(),源代码:
/*public String toString() {
Iterator<Entry<K,V>> i = entrySet().iterator(); //拿到每一个Entry对象放到迭代器里面
if (! i.hasNext()) //如果迭代器为空,没有元素
return "{}"; //返回{}
StringBuilder sb = new StringBuilder(); //如果有元素,创建StringBuilder
sb.append('{'); //添加{
for (;;) { //无限循环
Entry<K,V> e = i.next(); //拿到每一个Entry对象
K key = e.getKey(); //拿到键
V value = e.getValue(); //拿到值
sb.append(key == this ? "(this Map)" : key); //不断添加
sb.append('=');
sb.append(value == this ? "(this Map)" : value);
if (! i.hasNext())
return sb.append('}').toString(); //添加},再掉toString()转化成字符串
sb.append(',').append(' ');
}
}*/
自定义类:
public class Student {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
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 "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == 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;
}
}
LinkedHashMap
1、LinkedHashMap的概述:
public class LinkedHashMap<K, V> extends HashMap<K, V> implements Map<K, V>,哈希表和链表实现的Map接口,具有可预测的迭代次序。
java.util包下,使用需要导包。
2、案例演示:LinkedHashMap的使用。
import java.util.LinkedHashMap;
public class Demo6_LinkedHashMap {
public static void main(String[] args) {
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
lhm.put("张三", 23);
lhm.put("李四", 24);
lhm.put("赵六", 26);
lhm.put("王五", 25);
System.out.println(lhm);
}
}
3、LinkedHashMap的特点:
底层是链表实现的,可以保证怎么存就怎么取。属于HashMap派系,保证键的唯一。
TreeMap
1、TreeMap概述:
public class TreeMap<K, V> extends AbstractMap<K, V> implements NaigableMap<k, V>, Cloneable, Serializable,一个红黑树基于NavigableMap实现。
2、TreeMap的构造方法:
TreeMap(Comparator<? super K> comparator) 构造一个新的,空的树映射,该映射根据给定的比较器进行排序。
3、案例演示:TreeMap集合 键是Student 值是String的案例。键是二叉树排序。
import java.util.Comparator;
import java.util.TreeMap;
import com.bean.Student;
/**
* 案例演示:TreeMap集合 键是Student 值是String的案例。
*/
public class Demo7_TreeMap {
public static void main(String[] args) {
//按照传入的比较器进行比较
TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
public int compare(Student s1, Student s2) {
int num = s1.getName().compareTo(s2.getName()); //按照姓名比较
return num == 0 ? s1.getAge() - s2.getAge() : num;
}
});
tm.put(new Student("张三", 23), "北京");
tm.put(new Student("李四", 13), "上海");
tm.put(new Student("王五", 33), "广州");
tm.put(new Student("赵六", 43), "深圳");
System.out.println(tm);
//让对象自身具有比较性,让自定义类实现了Comparable接口,并重写了compareTo()。
/*TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
public int compare(Student s1, Student s2) {
int num = s1.getName().compareTo(s2.getName()); //按照姓名比较
return num == 0 ? s1.getAge() - s2.getAge() : num;
}
});
tm.put(new Student("张三", 23), "北京");
tm.put(new Student("李四", 13), "上海");
tm.put(new Student("王五", 33), "广州");
tm.put(new Student("赵六", 43), "深圳");
System.out.println(tm);*/
}
}
自定义类:
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
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 "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student o) {
int num = this.age - o.age; //以年龄为主要条件
return num == 0 ? this.name.compareTo(o.name) : num;//以姓名为次要条件
}
}
HashMap
2、案例演示:需求:统计字符串中每个字符出现的次数
import java.util.HashMap;
/**
* 需求:统计字符串中每个字符出现的次数
* 分析:
* 1.定义一个需要被统计字符的字符串。
* 2.将字符串转换为字符数组。
* 3.定义双列集合,存储字符串中字符以及字符出现的次数。
* 4.遍历字符数组获取每一个字符,并将字符存储在双列集合中。
* 5.存取过程中要做判断,如果集合中不包含这个键,就将该字符当作键,值为1存储;如果集合中包含这个键,就将值加1存储。
* 6.打印双列集合获取字符出现的次数。
*/
public class Test1 {
public static void main(String[] args) {
//1.定义一个需要被统计字符的字符串。
String s = "aaaabbbbcccccccccccddc";
//2.将字符串转换为字符数组。
char[] arr = s.toCharArray();
//3.定义双列集合,存储字符串中字符以及字符出现的次数。没有任何要求,首选HashMap。LinkedHashMap底层链表实现的,得保证怎么存怎么取。TreeMap要排序。HashMap是直接往里扔。
HashMap<Character, Integer> hm = new HashMap<>();
//4.遍历字符数组获取每一个字符,并将字符存储在双列集合中。
for(char c : arr) {
//5.存取过程中要做判断,如果集合中不包含这个键,就将该字符当作键,值为1存储;如果集合中包含这个键,就将值加1存储。
/*if(!hm.containsKey(c)) { //如果不包含这个键。
hm.put(c, 1); //把键和值为一存储。
}else { //如果包含这个键。
hm.put(c, hm.get(c) + 1); //把键和值加一存储。
}*/
hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1); //代码优化,三元运算符
}
//6.打印双列集合获取字符出现的次数。
for (Character key : hm.keySet()) { //自动拆箱,前面用char也可以.hm.keySet()代表所有键的集合。
System.out.println(key + "=" + hm.get(key)); //hm.get(key)代表根据键获取值。
}
}
}
3、案例演示:集合嵌套之HashMap嵌套HashMap。
import java.util.HashMap;
import com.bean.Student;
/**
* 案例演示:集合嵌套之HashMap嵌套HashMap。
* 需求:将第八十八个班级定义成一个双列集合,键是学生对象,值是学生的归属地。
* 将第九十九个班级定义成一个双列集合,键是学生对象,值是学生的归属地。
* 二者都是班级对象,所以为了便于统一管理,将二者添加到学校集合中。
*/
public class Demo8_HashMapHashMap {
public static void main(String[] args) {
//定义第88个班级
HashMap<Student, String> hm88 = new HashMap<>(); //Student类已经重写了hashCode()和equals()
hm88.put(new Student("张三", 23), "北京");
hm88.put(new Student("李四", 24), "北京");
hm88.put(new Student("王五", 25), "上海");
hm88.put(new Student("赵六", 26), "广州");
//定义第99个班级
HashMap<Student, String> hm99 = new HashMap<>();
hm99.put(new Student("唐僧", 1023), "北京");
hm99.put(new Student("孙悟空", 1524), "北京");
hm99.put(new Student("猪八戒", 1125), "上海");
hm99.put(new Student("沙和尚", 1226), "广州");
//定义学校,键是集合对象,值是班级。集合中嵌套集合。
HashMap<HashMap<Student, String>, String> hm = new HashMap<>();
hm.put(hm88, "第88个班级");
hm.put(hm99, "第99个班级");
//遍历双列集合
for (HashMap<Student, String> h : hm.keySet()) { //hm.keySet()代表的是双列集合中键的集合
String value = hm.get(h); //get(h)根据键对象获取值对象
//遍历键的双列集合对象
for (Student key : h.keySet()) { //h.keySet()获取集合中所有的学生键对象
String value2 = h.get(key);
System.out.println(key + " " + value2 + " " + value);
}
}
}
}
4、面试题:HashMap和Hashtable的区别。
HashTable概述:
public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, Cloneable, Serializable,该类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键值或值。
为了从散列表成功存储和检索对象,用作键的对象必须实现hashCode方法和equals方法。
java.util包下,使用需要导包。
命运类似vector从版本1.0出现,1.2改进实现List接口。Hashtable改进实现Map接口,被HashMap替代掉了。
第二单词首字母小写。
HashMap和Hashtable的共同点:
底层都是哈希算法。都是双列集合。
HashMap和Hashtable的区别:
Hashtable是JDK1.0版本出现的,是线程安全的,效率低;HashMap是JDK1.2版本出现的,是线程不安全的,效率高。
Hashtable不可以存储null键和null值,HashMap可以存储null键和null值。
案例演示 :HashMap和Hashtable的区别。
import java.util.HashMap;
import java.util.Hashtable;
public class Demo9_Hashtable {
public static void main(String[] args) {
HashMap<String, Integer> hm = new HashMap<>(); //为了后续代码能够继续执行,所以改进成能够存储null键和null值。
hm.put(null, 23); //存储null键
hm.put("李四", null); //存储null值
System.out.println(hm);
/* Hashtable<String, Integer> ht = new Hashtable<>();
// ht.put(null, 23); //NullPointerException
// ht.put("李四", null); //NullPointerException
System.out.println(ht);*/
}
}
Collections类
1、Collections类概述:
public class Collections extends Object,此类仅由静态方法组合或返回集合。它包含对集合进行操作的多态算法,“包装器”,返回由指定集合支持的新集合,以及其他一些可能的和最终的。
如果提供给它们的集合或类对象为null,则此类的方法都抛出一个NullPointerException 。
java.util包下,使用需要导包。
针对集合操作的工具类。类似于Arrays工具类 操作数组。
属性、方法均静态,构造方法被私有了。当一个类中所有的方法都是静态的,会私有这个类的构造方法。目的是不让其他类创建本类对象,直接类名.调用该类属性、方法。
2、Collections部分成员方法:
public static <T extends Comparable<? super T>> void sort(LIst<T> list) 根据其元素的natural ordering,按照升序排列指定的列表。列表中的所有元素必须实现Comparable接口。此外,列表中的所有元素都必须相互可比较 (即e1.compareTo(e2)不能为ClassCastException中的任何元素e1和e2 )。
这种保证是稳定的 :等同的元素将不会被排序作为排序的结果。
指定的列表必须是可修改的,但不能调整大小。
public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key) 使用二叉搜索算法搜索指定列表,以获得指定对象。在进行此调用之前,必须根据列表元素的自然顺序对列表进行生序排序(通过sort(List)方法)。如果没有对列表进行排序,则结果是不确定的。 如果列表包含多个与指定对象相等的元素,则不能保证将找到哪个元素。
返回:如果搜索键包含在列表中,则返回搜索键的索引;否则返回(-(插入点)-1)。插入点被定义为将键插入列表的那一点:即第一个大于此键的元素索引;如果列表中的所有元素都小于指定的键,则为list.size()。注意,这保证了当且仅当此键被找到时,返回的值将>=0;
public static <T extends Object & Comparable<? super T>> T max(Collection<?> coll) 根据其元素的自然顺序返回给定集合的最大元素。集合中的所有元素必须实现Comparable接口。此外,集合中的所有元素必须相互可比较 (即e1.compareTo(e2)不得为集合中的任何元素e1和e2投掷ClassCastException)。先对集合进行排序,再获取最后一个元素。默认按照以实现的compareTo()去排序,String类实现了compareTo()。
该方法遍历整个集合,因此它需要与集合的大小成比例的时间。
参数:coll - 要确定其最大元素的集合。
public static void reverse(List<?> list) 反转指定列表中元素的顺序。
public static void shuffle(List<?> list) 使用默认的随机源随机排列指定的列表。 所有排列都以大致相等的可能性发生。随机置换,可以用来洗牌。
3、案例演示:模拟斗地主洗牌和发牌,牌没有排序。
import java.util.ArrayList;
import java.util.Collections;
/**
* 案例演示:模拟斗地主洗牌和发牌,牌没有排序。
* 分析:
* 1.买一副扑克,其实就是自己创建一个集合对象,将扑克牌存储进去。
* 2.洗牌。
* 3.发牌。
* 4.看牌。
*/
public class Test2 {
public static void main(String[] args) {
//1.买一副扑克,其实就是自己创建一个集合对象,将扑克牌存储进去。
String[] num = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
String[] color = {"红桃","黑桃","方片","梅花"};
ArrayList<String> poker = new ArrayList<>();
//拼接花色和数字
for(String s1 : color) {
for(String s2 : num) {
poker.add(s1.concat(s2)); //连接两个字符串
}
}
poker.add("小王");
poker.add("大王");
//2.洗牌。
Collections.shuffle(poker);
//3.发牌。
ArrayList<String> gaojin = new ArrayList<>();
ArrayList<String> longwu = new ArrayList<>();
ArrayList<String> me = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
for (int i = 0; i < poker.size(); i++){
if(i >= poker.size() - 3) {
dipai.add(poker.get(i)); //将三张底牌存储在底牌集合中
}else if(i % 3 == 0) {
gaojin.add(poker.get(i));
}else if(i % 3 == 1) {
longwu.add(poker.get(i));
}else {
me.add(poker.get(i));
}
}
//4.看牌。
System.out.println(gaojin);
System.out.println(longwu);
System.out.println(me);
System.out.println(dipai);
}
}
4、案例演示:模拟斗地主洗牌和发牌并对牌进行排序的代码实现。
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
/**
* 案例演示:模拟斗地主洗牌和发牌并对牌进行排序的代码实现。
* 分析:
* 1.买一副扑克,其实就是自己创建一个集合对象,将扑克牌存储进去。
* 2.洗牌。
* 3.发牌。
* 4.看牌。
*/
public class Test3 {
public static void main(String[] args) {
//1.买一副扑克,其实就是自己创建一个集合对象,将扑克牌存储进去。
String[] num = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
String[] color = {"红桃","黑桃","方片","梅花"};
HashMap<Integer, String> hm = new HashMap<>(); //存储索引和扑克牌
ArrayList<Integer> list = new ArrayList<>(); //存储索引,方便洗牌
int index = 0;
//拼接扑克牌,并将索引和扑克牌存储在hm中
for(String s1 : num) { //获取数字
for(String s2 : color) { //获取颜色
hm.put(index, s2.concat(s1));
list.add(index); //将索引0到51添加到list集合中
index++;
}
}
hm.put(index, "小王"); //将小王添加到双列集合中
list.add(index); //将索引52添加到list集合中
index++;
hm.put(index, "大王"); //将大王添加到双列集合中
list.add(index); //将索引53添加到list集合中
//2.洗牌。
Collections.shuffle(list);
//3.发牌。
TreeSet<Integer> gaojin = new TreeSet<>();
TreeSet<Integer> longwu = new TreeSet<>();
TreeSet<Integer> me = new TreeSet<>();
TreeSet<Integer> dipai = new TreeSet<>();
for(int i = 0; i < list.size(); i++) {
if(i >= list.size() - 3) {
dipai.add(list.get(i)); //将三张底牌存储在底牌集合中
}else if(i % 3 == 0) {
gaojin.add(list.get(i));
}else if(i % 3 == 1) {
longwu.add(list.get(i));
}else {
me.add(list.get(i));
}
}
//4.看牌。
lookPoker(hm, gaojin, "高进");
lookPoker(hm, longwu, "龙五");
lookPoker(hm, me, "冯佳");
lookPoker(hm, dipai, "底牌");
}
/**
* 看牌
* 1.返回值类型void
* 2.参数列表HashMap, TreeSet, String name
*/
public static void lookPoker(HashMap<Integer, String> hm, TreeSet<Integer> ts, String name) {
System.out.print(name + "的牌是:");
for(Integer i : ts) { //i代表双列集合中的每一个键
System.out.print(hm.get(i) + " "); //通过键获取值
}
System.out.println();
}
}
泛型固定下边界
1、演示:? super E
import java.util.Comparator;
import java.util.TreeSet;
import com.bean.BaseStudent;
import com.bean.Student;
/**
* 泛型固定下边界 ? super E
* 泛型固定上边界 ? extends E
*/
public class Demo2_Genric {
public static void main(String[] args) {
/*ArrayList<Student> list1 = new ArrayList<>();
list1.add(new Student("张三", 23));
list1.add(new Student("李四", 24));
ArrayList<BaseStudent> list2 = new ArrayList<>();
list2.add(new BaseStudent("王五", 25));
list2.add(new BaseStudent("赵六", 26));
list1.addAll(list2); //可以把子类对象添加到父类的集合里面去 ? extends E 固定了上边界是Student,下边界是Student子类,可以是BaseStudent,也可以是其他Student
*/
TreeSet<Student> ts1 = new TreeSet<>(new CompareByAge());
ts1.add(new Student("张三", 33));
ts1.add(new Student("李四", 13));
ts1.add(new Student("王五", 23));
ts1.add(new Student("赵六", 43));
TreeSet<BaseStudent> ts2 = new TreeSet<>(new CompareByAge()); //可以使用父类的比较器进行排序 ? super E是拿出来。 ?extends E是放进去。把BaseStudent的对象拿出来到父类类型的比较器里去做比较。父类引用指向子类对象。
ts2.add(new BaseStudent("张三", 33));
ts2.add(new BaseStudent("李四", 13));
ts2.add(new BaseStudent("王五", 23));
ts2.add(new BaseStudent("赵六", 43));
System.out.println(ts2);
}
}
class CompareByAge implements Comparator<Student> { //比较器做完后,可以拿去给Student和Student所有的子类作比较
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge();
return num == 0 ? s1.getName().compareTo(s2.getName()) : num;
}
}
集合框架总结
单列集合Collection
List(存取有序,有索引,可以重复)
ArrayList:底层是数组实现,线程不安全,查找和修改快,增和删比较慢。
LinkedList:底层是链表实现,线程安全,增和删比较快,查找和修改比较慢。
Vector:底层是数组实现,线程安全,无论增删改查都慢。
查找和修改多:ArrayList;增删多:LinkedList;都多:ArrayList。
Set(存取无序,无索引,不可以重复)
HashSet:底层是哈希算法实现。
LinkedHashSet:底层是链表实现,但是也可以保证元素唯一,和HashSet原理一样。
TreeSet:底层是二叉树实现。
一般开发的时候不需要对存储的元素排序,所以在开发的时候大多用HashSet,HashSet的效率比较高。TreeSet在面试的时候比较多,问你有几种排序方式和这几种排序方式的区别。
双列集合Map
HashMap:底层是哈希算法,针对键。
LinkedHashMap:底层是链表,针对键。
TreeMap:底层是二叉树算法,针对键。
开发中HashMap比较多。除非对键进行排序,用TreeMap。