2023 1-1

day01 迭代器iterator的作用和使用

1.1 入门案例iterator.java

迭代器主要用于遍历,常用于集合


Iterator it = 集合对象.iterator();
while(it.hasNext()) {
   
	元素 = it.next();
}

增强 for循环


for(变量类型 变量 :数组/集合){
   
    *变量代表的就是集合或数组的元素*
}

示例

public class task02 {
   
    public static void main(String[] args) {
   
        Set<Integer> set  =new HashSet<>();
        Scanner read  = new Scanner(System.in);
        int length = read.nextInt();
        for(int i = 0 ;i < length ;i++){
   
            set.add(read.nextInt());
        }
        for(Integer i: set){
    //这里用Integer而不用int是因为 set 已经指定了泛型Interger,这里的i代表的就是 集合或数组的元素
            System.out.print(i+" ");
        }
        Iterator it = set.iterator();
        while(it.hasNext()){
   
            System.out.print(it.next()+" ");
        }
    }
}
//输入: 5 1 2 3 4 5
//输出: 1 2 3 4 5 1 2 3 4 5

1.2 上转型对象

上转型对象思想用一个通俗的思想来了解就是:将老虎上转成动物,但是此时老虎失去了老虎的具体特性
这个例子很贴切:

  1. 普通对象可以操纵继承自父类的变量、子类新增的对象、继承或重写的方法、新增的方法,但是不可以操纵父类隐藏的变量。
  2. 上转型对象可以操纵父类隐藏的变量、继承的变量、继承或者重写的方法(父类原本就包含的,也就是整个动物范畴的),但是却不可以操纵新增的变量,也不可以操纵新增的方法(失去了老虎的特性)
  3. 若想让 上转型对象使用子类新增的功能,可以将对象的上转型对象再强制转换到一个子类对象.
Tager taiger = (Tager)animal;

1.3 集合泛型

//泛型不支持基本数据类型,这里的不支持指的是 Set<Integer> 而不是 Set<int>
程序中可能通过数组来保存多个对象,因为数组长度是不可变的。JDK中提供了一些特殊的类,这些类可以存储任何对象,并且长度可变,在java中这些类被为集合。集合类位于java.util包中。

集合分类

  • 单列集合 Collection 接口
  • 双列集合 Map 接口

8.1 Collection接口

java.util.Collection是所有单列集合的父接口,因此在Collection中定义了单列集合ListSet通用的一些方法。

方法声明 功能描述
boolean add(Object o) 向集合中添加一个元素
boolean addAll(Collection c) 增加一个集合(多个元素)
void clear() 清空集合
boolean remove(Object o) 删除集合中的一个对象(元素)
boolean removeAll(Collection c) 删除一个集合(多个元素)
boolean isEmpty() 是不是空的
boolean contains(Object o) 判断集合有没有这个元素
boolean containsAll(Collection c) 判断集合中有没有参数集合
Iterator iterator() 返回一个遍历迭代器
int size() 返回集合的元素个数

注:addAll(Collection c) 中参数是一个单列集合,jdk17以后这种单列集合 或者 双列集合在调用时已经可以可以这样写了:
addAll(Set.of(1,2,3,4,5,6));//这里的S必须要大写,因为参数时一个单列集合对象

8.1.1 List接口

List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地将实现了List接口的对象称为List集合。

方法声明 功能描述
void add(int index,Object element)
boolean addAll(int index,Collection c)
Object get(int index)
Object remove(int index)
Object set(int index,Object element)
int indexOf(Object o)
int lastIndexOf(Object o)
List subList(int fromIndex,int toIndex)
ArrayList
extends AbstractList<E>

java.util.ArrayList类是List接口的一个实现类,此对象相当于动态的数组。

实例化ArrayList类

(不支持多线程)和Vector作为对比,但是ArrayList效率较高,用的也更多

//实例化 ArrayList
ArrayList list1 = new ArrayList(); //普通对象
//var list2 = new ArrayList();
List list3 = new ArrayList(); //上转型对象

//此方法实例出的对象,是只读的(不能添加 删除 移动位置,优点是能够快速建立集合实例对象)
List list4 = List.of();//这种方法也可以实例化 对象
//list4.add(10); 此行是错误的,因为List.of() 对象是只读的

String[] arr = {
   "java","javascript","python","html"};
//此方法实例出的对象,是只读的
List list5 = Arrays.asList(1,2,3);
//list5.add(10);

List list6 = new ArrayList(list5);

注:
List list4 = List.of();//这种方法实例化对象是只读的,可以增加或删除或者移动位置
List list2 = List.of(1,2,4,6,7); list2.add(3);//这样写是错误的

ArrayList的排序
  • 数字
List<Integer> list = new ArrayList<>();
List list1 = List.of(1,4,2,3,6);
list.addAll(list1);
//升序排序(默认升序)
Collections.sort(list);
Collections.sort(list,(a,b)->a-b);
//降序排序
Collections.sort(list,(a,b)->b-a);

//乱序
Collections.shuffle(list);//这里参数写成list就错了,以为用.of()实例化的对象只读
  • 字符串(本质还是数字,按照ASCII码)
//a-z升序
          Collections.sort(list);
          //Collections.sort(list, (a,b)->a.compartTo(b));
          System.out.println(list);
  
          //z-a降序
          Collections.sort(list,(a,b)->b.compareTo(a));
          System.out.println(list);
          
          //根据字符串升序,进行排序 升序
          Collections.sort(list,(a,b)->a.length()-b.length());
          System.out.println(list);
  
          //降序
          Collections.sort(list,(a,b)->b.length()-a.length());
          System.out.println(list);
  • 自定义
    如果使用集合工具的排序方法,Collections.sort(list)此类必须实现Comparable接口,实现方法;而用实例的对象调用继承自 Collections.sort()方法时 ,需要用lambda表达时指定Comparable的比较方法
public class SortArrayList {
   
    public static void main(String[] args) {
   
        List<Book> list = new ArrayList<>();
        list.addAll(List.of(new Book("a",1),new Book("b",5),new Book("c",2)));
        //实现方法一
        //用lamda表达式来重写compareTo()方法,按照book的Id来排序
        list.sort((a,b)->(a.getId()-b.getId())); 
        //,按照book的name来排序
        list.sort((a,b)->(b.getName().compareTo(a.getName())));
        //实现方法二,此时的Book 必须实现comparable接口
        /* public class Book implements Comparable<Book>{ @Override public int compareTo(Book o) { return o.name.compareTo(name); // 参数是b, 当前 book 是a } } */
        Collections.sort(list);
        //-------------三种遍历集合的方法-----------------------
        //1.遍历效率低
        System.out.println(list);
        //2.遍历效率高
        Iterator it = list.iterator();
        while(it.hasNext()){
   
            System.out.print(it.next()+" ");
        }
        //3.
        for(Book i : list){
   
            System.out.print(i+" ");
        }
        String a = new String("wo");
        System.out.println(a.compareTo("a"));

    }
}

8.2 Map接口

map接口是一个双列集合,每个元素有一个键值 对 Map<K,V>

public interface Map<K, V> {
   
    
}

8.2.1 HashMap

Map<K,V> 实现类为 HashMap<K,V>,HashMap 实例化,添加,判断,清空,删除,替换

HashMap基本使用

package cn.webrx;

import java.util.HashMap;
import java.util.Map;

public class HashMap1 {
   
    public static void main(String[] args) {
   
        //没有使用泛型,不推荐
        //Map map = new HashMap();

        //实例化Map对象
        Map<String,Book> map = new HashMap<>();

        //添加元素,添加元素时,如果Key值存在,则覆盖元素
        map.put("b01",new Book(10,"《java程序入门》",35));
        map.put("b02",new Book(22,"《数据库技术》",55));
        Book book = new Book(33,"《前端开发》",30);
        map.put("b02",book);

        //判断
        //判断有没有Key 为 b01 true
        System.out.println(map.containsKey("b01"));
        //判断有没有Key 为 b03 false
        System.out.println(map.containsKey("b03"));

        //判断有没有Value 为 new Book(33,"《前端开发》",30)
        //System.out.println(map.containsValue(new Book(33,"《前端开发》",30)));
        System.out.println(map.containsValue(book));


        //编辑,重新设置或修改值
        map.replace("b02",new Book(55,"《java微服务开发实战》",68));

        //删除清空
        //map.clear();
        //map.remove("b02");

        //获取指定元素 get(String key)
        System.out.println(map.get("b01"));
        System.out.println(map.get("b11"));
        //获取指定key元素,如果不存在,则使用默认值返回对象
        System.out.println(map.getOrDefault("b11",new Book(100,"《入门书籍》",35)));
        System.out.println(map.getOrDefault("b02",new Book(100,"《入门书籍》",35)));


        //获取map集合的元素个数
        System.out.println(map.size());

        System.out.println(map);

    }
}

HashMap遍历KeySet Values

package cn.webrx;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


public class HashMap2 {
   
    public static void main(String[] args) {
   
        Map<String,String> map = new HashMap<>();
        map.put("bj","北京");
        map.put("tj","天津");
        map.put("hn","河南");
        map.put("sh","上海");

        //第一种遍历方式 keySet()方法返回Set集合
        Set<String> keys = map.keySet();
        for(String k : keys){
   
            //System.out.println(k);
            System.out.printf("map[\"%s\"] = %s%n",k,map.get(k));
        }

        //第二种遍历方式 values() 返回Collection<String> 集合
        Collection<String> values = map.values();
        for(String v : values){
   
            System.out.println(v);
        }

        //第三种遍历方式 entrySet() 返回一个Set<Map.Entry<String,String>> 集合
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for(Map.Entry<String,String> e : entries){
   
            //System.out.println(e);
            System.out.println(e.getKey());
            System.out.println(e.getValue());
        }

        //第四种遍历方式 使用迭代器接口Iterator 接口
        Iterator<String> iterator = map.values().iterator();
        while(iterator.hasNext()){
   
            System.out.println(iterator.next());
        }

        Iterator<String> iterator1 = map.keySet().iterator();
        while(iterator1.hasNext()){
   
            String key = iterator1.next();
            System.out.println(key);
            System.out.println(map.get(key));
        }
    }
}

以上遍历主要Iterator遍历集合方式、for循环遍历集合方式,Lambda遍历集合方式,根据具体需求选用不同的方式,通过Iterator方式循环删除数据是安全的,for方式循环删除数据非安全,Lambda方式循环删除 数据非安全,通过Iterator方式的效率也很高

HashMap不是线程同步,如果需要使用线程并发,可以使用HashTable对象

Hashtable<K,V> implements Map<K,V>

Hashtable:底层也是哈希表,是同步的,是一个单线程结合,是线程安全的集合,速度慢

HashMap:底层也是哈希表,但是线程不安全的集合,是多线程集合,速度快

HashMap(还有之前学的所有集合):都可以存储null键,null值

Hashtable:不能存储null键,null值

8.2.2 TreeMap

  1. 是一个有序的key-value集合,它是通过红黑树实现的。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

  2. 是继承了AbstractMap,也是以key-value集合存储。实现了NavigableMap接口,可以支持一系列的导航方法。

    比如返回有序的key集合。实现了Cloneable克隆接口。实现了java.io.Serializable序列化接口。另外,TreeMap是非线程同步的。

构造方法

TreeMap() 使用键的自然顺序构造一个新的、空的树映射。

TreeMap(Comparator comparator) 构造一个新的、空的树映射,该映射根据给定比较器进行排序。

TreeMap(Map m) 构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序 进行排序。

TreeMap(SortedMap m) 构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射。

TreeMap<String, Integer> tm = new TreeMap<>();
TreeMap<String, Integer> tm = new TreeMap<>((a, b) -> Math.random() > .5 ? 1 : -1);
TreeMap<String, Integer> tm = new TreeMap<>((a, b) -> a.compareTo(b));
TreeMap<String, Integer> tm = new TreeMap<>(Comparator.reverseOrder());
TreeMap<String, Integer> tm = new TreeMap<>((a,b)->b.compareTo(a));
TreeMap<String, Integer> tm = new TreeMap<>((a,b)->a.compareTo(b));
TreeMap<String, Integer> tm = new TreeMap<>(String::compareTo);

//升序
TreeMap<Double, String> t2 = new TreeMap<>();
//TreeMap<Double, String> t2 = new TreeMap<>(Double::compareTo);

//乱序
//TreeMap<Double, String> t2 = new TreeMap<>((a, b) -> Math.random()>.5 ? 1 : -1);

//降序
//TreeMap<Double, String> t2 = new TreeMap<>((a, b) -> a < b ? 1 : -1);

//升序
//TreeMap<Double, String> t2 = new TreeMap<>((a, b) -> a > b ? 1 : -1);

TreeMap<Student, String> t3 = new TreeMap<>((a,b)->a.getId()-b.getId());
//key String
t3.put(new Student(1,"李四1"),"郑州");
t3.put(new Student(6,"李四2"),"北京");
t3.put(new Student(2,"李四3"),"天津");
t3.put(new Student(33,"李四33"),"上海");
t3.put(new Student(4,"李四5"),"上海");
System.out.println(t3);
常用方法
方法 说明
public NavigableMap<K,V> descendingMap() 把集合逆序返回
方法 说明
put(K key, V value) 将指定值与此映射中的指定键进行关联
int size() 返回此集合元素的个数
V remove(Object key)
putAll(Map map) 将指定映射中的所有映射关系复制到此映射中
Collection values()
Set keySet() 本质是TreeSet
Map.Entry<K,V> entrySet() 返回Set<Map.Entry<K,V>>
get(Object key)
containsKey(Object key)
firstEntry() 返回集合第一个Map.Entry<K,V>
lastEntry()
firstKey() 返回集合第一个元素的Key
lastKey()
boolean remove(Object key, Object value)
containsValue()
public static void main(String[] args) {
   
        TreeMap<Integer, String> tm = new TreeMap<>();
        tm.put(1, "hello1");
        tm.put(2, "hello22");
        tm.put(3, "hello333");
        tm.put(10, "hello10");
        tm.put(4, "hello4444");
        System.out.println(tm);
        //.descendingMap() 返回一个Map 根据key降序,对原来的TreeMap没有改变
        Map<Integer,String> t2 = tm.descendingMap();
        System.out.println(tm);
        System.out.println(t2);
}
集合总结

Collection List ArrayList LinkedList
Set HashSet TreeSet

Map Iterator 接口 HashMap TreeMap

ArrayList LinkedList
HashSet TreeSet
HashMap TreeMap

Vector
HashTable

Vetcor

java.util.Vector

Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:

  • Vector 是同步访问的。(非线程安全、线程安全)
  • Vector 包含了许多传统的方法,这些方法不属于集合框架。

Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。

Vector和ArrayList功能是一样的,ArrayList是非线程安全,在多线程使用中同步操作时,会出现脏读,Vetctor的各个方法添加了同步锁synchronized支持线程安全。在单线程程序中,ArrayList使用的最多,速度快,在多线程编程中,如果线程间在同步数据,应该使用Vector。

HashTable

和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6o60J431-1672750446862)(assets/image-20221107173855061.png)]

HashTable是线程安全的,HashMap是非线程安全。如果在单线程main线程程序中,使用了线程安全的工具类,效率就低,根据使用量上来说还是HashMap使用的多。

集合接口及工具类总结:

Collection 接口
List 接口
ArrayList 动态数组,有序 插入删除速度慢,读取速度
LinkedList 双向链表,插入删除速度快,读取速度慢
Vector 动态数组,线程安全
Set 接口
HashSet 唯一集合,无序
TreeSet 唯一集合,是有序

Map 接口
HashMap K,V键值对集合,双列集合
TreeMap 根据key有序的map集合
Hashtable 和 HashMap一样,双列集合,线程安全