1. list:(有序可重复)
-
ArrayList
:底层实现是数组,但是没有定义具体的长度和大小,有下标,所以查询快,增删慢,线程不安全 -
LinkedList
: 底层是链表,因为有指针所以增删快查询慢,线程不安全 -
Vector
:底层是数组,线程安全,有下标所以查询快增删慢,有synchronized
修饰,现已被ArrayList
替代
1.1. list集合遍历
for(int i = 0; i < list.size(); i++) {
Student s = (Student)list.get(i);
}
ListIterator lit = list.listIterator(); //获取迭代器(List集合特有的)
while(lit.hasNext()) {
String str = (String)lit.next(); //向下转型
if("world".equals(str)) {
//list.add("javaee"); //遍历的同时在增加元素,并发修改ConcurrentModificationException
lit.add("javaee");
}
}
ListIterator lit = list.listIterator(); //获取迭代器
while(lit.hasNext()) {
System.out.println(lit.next()); //获取元素并将指针向后移动
}
while(lit.hasPrevious()) {
System.out.println(lit.previous()); //获取元素并将指针向前移动
}
2. Set:(无序不重复)
-
HashSet
:底层是hash
表结构,实现了set
接口,其实是基于hashMap
实现的,不能有null
值,在添加数据时(add
方法),会调用对象的hashcode()
方法在set
中去查找,比较要添加的值和set
中的值若是hash
值相等,若是相等则用equals
方法比较,如果不相等,则添加(说明没有重复的值) -
TreeSet
:底层是二叉树结构,不可以存重复对象,根据数据自身进行排序,如果没有可比性,则实现comparable
接口重写compareTo
方法(该方法是使某个对象具有可比性),也可实现compartor
接口重写compare
方法(该方法是使某个集合具有可比性)
2.1. Set集合,无索引,不可以重复,无序(存取不一致)
HashSet<String> hs = new HashSet<>(); //创建HashSet对象
boolean b1 = hs.add("a");
boolean b2 = hs.add("a"); //当向set集合中存储重复元素的时候返回为false
hs.add("b");
hs.add("c");
hs.add("d");
2.2. LinkedHashSet是HashSet的子类,底层是链表实现的,有序
LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("a");
lhs.add("a");
lhs.add("b");
2.3. TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一
* 当compareTo方法返回0的时候集合中只有一个元素
* 当compareTo方法返回正数的时候集合会怎么存就怎么取
* 当compareTo方法返回负数的时候集合会倒序存储
TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("zhangsan", 23));
ts.add(new Person("lisi", 13));
ts.add(new Person("wangwu", 33));
ts.add(new Person("zhaoliu", 43));
TreeSet<String> ts = new TreeSet<>(new CompareByLen());
ts.add("aaaaaaaa");
ts.add("z");
ts.add("wc");
ts.add("nba");
class CompareByLen /*extends Object*/ implements Comparator<String> {
@Override
public int compare(String s1, String s2) { //按照字符串的长度比较
int num = s1.length() - s2.length(); //长度为主要条件
return num == 0 ? s1.compareTo(s2) : num; //内容为次要条件
}
}
3. Map:(存键值对)
-
HashMap
:底层是哈希表(数组+链表)结构,线程不安全,可以存一个null
键和多个null
值,若要线程安全则Collections.synchronizedMap()
方法,在添加新值的时候(put
)会去计算将添加key
值的hashCode
,hashCode%length = i
,要存的entry
,若此时entry
上已经有值了那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。 -
HashTable
:底层是哈希表(数组+链表)结构,线程安全,不可以存null
键或者null
值 -
TreeMap
:底层实二叉树结构,可以存重复对象,实现comparable
接口重写compareTo
方法(该方法是使某个对象具有可比性),也可实现compartor
接口重写compare
方法(该方法是使某个集合具有可比性)
3.1. Map集合的迭代
//获取所有的键
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));
}
//Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并存储在Set集合中
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
//获取每一个对象
Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
while(it.hasNext()) {
//获取每一个Entry对象
Map.Entry<String, Integer> en = it.next(); //父类引用指向子类对象
//Entry<String, Integer> en = it.next(); //直接获取的是子类对象
String key = en.getKey(); //根据键值对对象获取键
Integer value = en.getValue(); //根据键值对对象获取值
System.out.println(key + "=" + value);
}
//使用增强for循环遍历
for(Entry<String, Integer> en : map.entrySet()) {
System.out.println(en.getKey() + "=" + en.getValue());
}
3.2. HashMap
HashMap<Student, String> hm = new HashMap<>();
hm.put(new Student("张三", 23), "北京");
hm.put(new Student("张三", 23), "上海");
3.3. LinkedHashMap
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
lhm.put("张三", 23);
lhm.put("李四", 24);
3.4. TreeMap
public static void main(String[] args) {
TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
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("赵六", 43), "深圳");
tm.put(new Student("王五", 33), "广州");
}
补充:
1.HashMap和TreeMap的区别
-
HashMap
:数组方式存储key/value
,线程非安全,允许null
作为key
和value
,key
不可以重复,value
允许重复,不保证元素迭代顺序是按照插入时的顺序,key
的hash
值是先计算key的hashcode
值,然后再进行计算,每次容量扩容会重新计算所以key
的hash
值,会消耗资源,要求key
必须重写equals
和hashcode
方法 -
TreeMap
:基于红黑二叉树的NavigableMap
的实现,线程非安全,不允许null
,key
不可以重复,value
允许重复,存入TreeMap
的元素应当实现Comparable
接口或者实现Comparator
接口,会按照排序后的顺序迭代元素,两个相比较的key
不得抛出classCastException
。主要用于存入元素的时候对元素进行自动排序,迭代输出的时候就按排序顺序输出
2.HashMap的排序
public static void main(String[] args) {
HashMap<Integer, User> map = new HashMap<Integer, User>();
map.put(1, new User("张三", 26));
map.put(3, new User("李四", 32));
map.put(2, new User("王五", 23));
System.out.println("排序前:"+map);
//TODO 对hashmap排序实现age字段按倒序排列
HashMap<Integer,User> sortHashMap = sortHashMap(map);
System.out.println("排序后:"+sortHashMap);
}
//对HashMap排序
public static HashMap<Integer, User> sortHashMap(HashMap<Integer, User> map) {
LinkedHashMap<Integer, User> linkedHashMap = new LinkedHashMap<>();
//TODO 将map 转化成Collection
Set<Entry<Integer,User>> set = map.entrySet();
ArrayList<Entry<Integer,User>> list = new ArrayList<>(set);
Collections.sort(list, new Comparator<Entry<Integer,User>>() {
@Override
public int compare(Entry<Integer, User> o1, Entry<Integer, User> o2) {
//排序规则
//前一个对象-后一个对象=正序
return o2.getValue().getAge()- o1.getValue().getAge();
}
});
//TODO 将list的内容添加到linkedHashMap中
for (int i = 0; i < list.size(); i++) {
linkedHashMap.put(list.get(i).getKey(), list.get(i).getValue());
}
return linkedHashMap;
}
3. HashMap问答
- 1.7 的
HashMap
的数据结构是怎么样的?
数组 + 链表 - 1.7 的
HashMap
怎么在链表上添加数据,在链表的前⾯还是链表的后⾯?
「头插法」 - 1.7
HashMap
是怎么预防和解决Hash
冲突的?
「⼆次哈希」 + 「拉链法」 - 1.7
HashMap
默认容量是多少?为什么是 16 可以是 15 吗?
16,需要是 2 的幂次⽅ - 1.7
HashMap
的数组是什么时候创建的?
⾸次调⽤put
时 - 1.7 和 1.8 数据结构有什么不同?
1.8 增加了转换为红⿊树 - 插⼊数据的⽅式?
1.7 的链表从前⾯插⼊,1.8 的链表从后⾯插⼊ - 扩容后存储位置的计算⽅式?
1.7 通过再次indexFor()
找到数组位置,1.8 通过⾼低位的桶直接在链表尾
部添加 HashMap
什么时候会把链表转化为红⿊树?
链表⻓度超过 8 ,并且数组⻓度不⼩于 64