集合
- 动态的,不需要指定长度。
- 集合中只能放 引用/对象 数据类型,若相放基本数据类型 变成包装类。
Collection接口
ArrayList<String> list = new ArrayList<>();
// 批量添加
Collections.addAll(list,"D","c","a","b");
// 利用自然排序
Collections.sort(list);
// 集合中泛型如果是自定义类型 , 也可以实现定制排序
Collections.sort(list2, new Comparator<Student2>() {
@Override
public int compare(Student2 o1, Student2 o2) {
return -(o1.age-o2.age);
}
});
System.out.println(list2);
// 将集合中元素进行 翻转
Collections.reverse(list2);
//替换集合中的元素, 根据地址进行替换
Collections.replaceAll(list2, student, new Student2(5));
最大值最小值
// 要求集合中的类实现了 自然排序
// 前提是自定义类实现了Comparable<Studenr2>接口
Student2 max = Collections.max(list2);
System.out.println(max);
Student2 min = Collections.min(list2);
System.out.println(min);
// 定制排序
Student2 max2 = Collections.max(list2, new Comparator<Student2>() {
@Override
public int compare(Student2 o1, Student2 o2) {
return o1.age-o2.age;
}
});
System.out.println(max2);
Student2 min2 = Collections.min(list2, new Comparator<Student2>() {
@Override
public int compare(Student2 o1, Student2 o2) {
// TODO Auto-generated method stub
return o1.age-o2.age;
}
});
System.out.println(min2);
List接口:有序且允许重复
ArrayList:线程不安全,效率高
Vector:线程安全,效率低
LinkedList
ArrayList:底层是大小可变的数组,线程不安全
特点:有序且允许重复
场景:适用于频繁操作的场景
初始长度是10,如果有特殊需求,开始就要存储大量数据,则通过构造方法单独设置
优点:遍历速度快,修改速度快
缺点:指定下标插入和删除的时候,可能会移动大量元素,效率较低
遍历
// 1. 产生副本 遍历的是副本
// 2. 遍历副本的时候, 修改的是源集合,
for (String string : list) {
if(string instanceof String){
list.remove(string);
}
}
// 1. 产生副本 遍历的是副本
// 2. 遍历副本的时候, 删除副本的元素,
// 3. 将副本替换掉原集合
Iterator<String> it = list.iterator();
while(it.hasNext()){
String obj = it.next();
if(obj instanceof String){
it.remove();
}
}
// 可以有顺序的迭代器
// 可以有顺序的 迭代器 指针默认在 所有元素的前面
ListIterator<Integer> listIterator = list.listIterator();
// 将指针放到 下标为1的元素位置
ListIterator<Integer> listIterator2 = list.listIterator(1);
while(listIterator2.hasPrevious()){
Integer num = listIterator2.previous();
if(num==3){
// 在遍历过程中 添加元素
listIterator2.add(6);
}
}
// 遍历的就是原集合,不是副本
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
if(str instanceof String){
list.remove(str);
// 产生过删除操作的位置,则 i--, 重新检查一遍
i--;
}
}
LinkedList:底层数据结构是双向链表 堆栈结构
特点:有序且允许重复
**优点:插入和删除的时候,效率高**
**缺点:遍历和修改的时候,效率低**
// 创建LinkedList集合对象
LinkedList<String> list = new LinkedList<>();
list.add("a");
// 在指定位置插入一个元素。
add(int index, E element);
// 添加头和尾的操作
list.addFirst("z");
list.addLast("y");
//当队列为空时候,使用add方法会报错,而offer方法会返回false。
list.offerFirst("z");
list.offerLast("y");
// 获取头和尾的对象
String first = list.getFirst();
String last = list.getLast();
// 获取头和尾的对象
String peekFirst = list.peekFirst();
String peekLast = list.peekLast();
// 获取集合开头和结尾的元素,并且在集合中移除
String pollFirst = list.pollFirst();
String pollLast = list.pollLast();
// 弹栈 删除第一个元素
String pop = list.pop();
System.out.println(pop);
System.out.println(list);
// 压栈 在第一个元素前添加
list.push("z");
System.out.println(list);
// 删除指定元素
list.remove("a");
// 删除头部元素
list.removeFirst();
// 删除尾部元素
list.removeLast();
list集合遍历
for (String string : list) {
System.out.println(string);
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
iterator.next();
}
LinkedList与ArrayList区别
ArrayList和LinkedList都实现了List接口,他们有以下的不同点:
.LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素
.相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引
练习:要求向集合中添加10个不重复的10~20之间的随机数
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 10; i++) {
int num = (int)(Math.random()*(20-10+1)+10);
if(!list.contains(num)){
list.add(num);
}else{
i--;
}
}
System.out.println(list);
Vector:线程同步,底层是数组
Vector 由于使用了 synchronized 方法(线程安全),通常性能上较 ArrayList 差
Set接口:无序且不允许重复
初始容量是16
加载因子:扩容:16*0.75 = 12 16+12 = 28;
当链表长度达到8个的时候,改成红黑树,当删除到六个的时候就改成链表
HashSet
添加元素时,执行的流程:
当调用add方法的时候,add方法内部会自动的调用hashcode计算哈希吗,得到哈希吗之后,会通过哈希表进行比较查看是否有重复元素, 如果没有重复元素,则可以直接添加到集合, 如果有重复元素 则调用equals进行比较. equals方法结果如果为false,则添加到集合, 如果equals的结果为true则不添加
HashCode:获取哈希码
public static void add(Student stu){
// 1. 先调用对象的hashcode方法的到一个哈希值
int hashCode = stu.hashCode();
//2. 去哈希表中查找遍历, 是否有相同的哈希值
// 3. 如果没有相同的哈希值, 则直接存入集合
}
public static void add2(Student stu){
// 1. 先调用对象的hashcode方法的到一个哈希值
int hashCode = stu.hashCode();
//2. 去哈希表中查找遍历, 是否有相同的哈希值
//3. 找到相同的了哈希值,但是哈希值相同不一定是相同的对象
// age height; 6 9
// 9 6
//4. 则调用equals方法 进行 判断 每个属性是否相同,
//5. 如果各个属性都相同, 就是相同对象,则不添加
// 如果属性不同,则认为是不同的对象, 就添加
// equals
}
// 集合的嵌套
HashSet<ArrayList<String>> set2 = new HashSet<>();
特殊情况:内容不同 哈希码相同,也要进行存储,利用equals进行对比
Treeset
TreeSet 可以排序的, 泛型是自定义类的话 必须实现排序接口
Comparable 自然排序
HashSet与TreeSet区别
HashSet是由一个hash表来实现的,因此,它的元素是无序的
TreeSet是由一个树形的结构来实现的,它里面的元素是有序的
自然排序
- 在泛型中的自定义类中实现Comparable<自定义类名>
- 重写compareTo方法
- 创建TreeSet集合,向集合中添加元素
定制排序
- 编写自定义类
- 单独定义比较器类,实现Comparator<自定义类>
- 重写compare方法
- 创建TreeSet集合,new TreeSet<>(new 比较器对象)
- 向集合中添加元素
定制排序比自然排序耦合性低
定制排序优先级高
如果集合中添加的是自定义类型, 则必须实现排序方式中的一种,否则会报ClassCastException
public class StudentComparator implements Comparator<Student>{
// compare 和Comparato方法一样
@Override
public int compare(Student o1, Student o2) {
// o1--->this
// o2--> o用
// 年龄降序排序
if(o1.age>o2.age){
return -1;
}else if(o1.age<o2.age){
return 1;
}
return 0;
}
定制排序的 匿名内部类写法
TreeMap<Person, Integer> map2 = new TreeMap<>(new Comparator<Person>() {
// 排序也只能针对 键起作用, 不能针对值起作用
@Override
public int compare(Person o1, Person o2) {
return o1.age -o2.age;
}
});
HashSet与HashMap的关系
HashSet中会有一个HashMap的属性,每当创建一个HashSet,就会自动创建一个HashMap
添加数据的时候,是向HashMap的键中添加一个数据
Map接口
key 不可重复
value 可以重复,若重复 被新的覆盖
HashMap
用哈希表存放,使用频率最高
HashMap<String, Integer> map = new HashMap<>();
// 添加元素
map.put("a", 1);
// 如果键有相同,键只能存储一份, 但是新的值覆盖旧的值
map.put("a", 5);
// 判断是否包含指定的键
boolean b = map.containsKey("a");
// 判断是否包含指定的值
boolean b2 = map.containsValue(13);
// 判断是否为空(集合中没有元素) 没有元素 结果为true, 有元素结果为false
boolean empty = map.isEmpty();
// 根据键 得到值
Integer value = map.get("a");
// 如果自定义类放在键的上 是 不允许重复的, 如果自定义类在键的位置上, 则可以通过重写hashcode和equals实现,内容相同只存一个键
HashMap<Student, Integer> map2 = new HashMap<>();
// 如果自定义类放在值的上 是 不允许重复的. 自定义类放在值的位置上, 即使重写了hashcode和equals没用
HashMap<Integer, Student> map3 = new HashMap<>();
Map集合遍历
不能通过 增强for循环 直接遍历集合
Set<Map.Entry<K,V>> entrySet()
Set keySet()
Collection values()
通过一些方式进行转换, 转换成 set,Collection这种集合进行遍历
1. 将集合中所有的键全部拿到
Set<String> keys = map.keySet();
// a b c
for (String key : keys) {
// key = a b c
Integer value2 = map.get(key);
System.out.println(key+"="+value2);
}
2. Collection<V> values() 只能拿到所有的值 不能遍历key
只能通过键找值,不能通过值找键
Collection<Integer> values = map.values();
for (Integer integer : values) {
System.out.println(integer);
}
3. Set<Map.Entry<K,V>> entrySet()
Set<Entry<String,Integer>> set = map.entrySet();
for (Entry<String, Integer> entry : set) {
String key = entry.getKey();
Integer value2 = entry.getValue();
System.out.println(key+"="+value2);
}
4.通过迭代器的方式
Iterator<Entry<String, Object>> it = map.entrySet().iterator();
while(it.hasNext()){
Entry<String, Object> entry = it.next();
System.out.println("key:"+entry.getKey()+
" key:"+entry.getValue());
}
TreeMap:
排序也只能针对 键起作用, 不能针对值起作用
TreeMap<Person,Integer> map = new TreeMap<>(new PersonComparator());
map.put(new Person("zhangsan", 16), 1);
// 定制排序 匿名内部类的写法
TreeMap<Person, Integer> map2 = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
return o1.age -o2.age;
}
});
定制排序
public class PersonComparator implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return -(o1.age-o2.age);
}
}
迭代器