• Java集合内容


    Java的集合类定义在java.util包中,支持泛型,主要提供了3种集合类,包括ListSetMap。Java集合使用统一的Iterator遍历。

    1、List遍历

    实现了Iterator接口的集合类都可以直接用for each循环来遍历,Java编译器本身并不知道如何遍历集合对象,但它会自动把for each循环变成Iterator的调用

    public class Main {
    public static void main(String[] args) {
    List<String> list = List.of("AA", "BB", "CC");
    for (String s : list) {
    System.out.println(s);
    }
    }
    }

    2、List和Array转换

    List变为Array有三种方法

    第一种是调用toArray()方法直接返回一个Object[]数组              Object[] array = list.toArray();

    第二种方式是给toArray(T[])传入一个类型相同的ArrayList内部自动把元素复制到传入的Array中          Integer[] array = list.toArray(new Integer[3]);

    第三种方式是通过List接口定义的T[] toArray(IntFunction<T[]> generator)方法                  Integer[] array = list.toArray(Integer[]::new);

    3、List是一种有序链表:List内部按照放入元素的先后顺序存放,并且每个元素都可以通过索引确定自己的位置

    List提供了boolean contains(Object o)方法来判断List是否包含某个指定元素。此外,int indexOf(Object o)方法可以返回某个元素的索引,如果元素不存在,就返回-1

    List中添加的"C"和调用contains("C")传入的"C"不是同一个实例,但是取到了元素和索引,因为List内部并不是通过==判断两个元素是否相等,而是使用equals()方法判断两个元素是否相等

    public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("A");
    list.add("B");
    list.add("C");
    System.out.println(list.contains("B")); // true
    System.out.println(list.indexOf("B")); // 1
    System.out.println(list.contains(new String("C"))); // true
    System.out.println(list.indexOf(new String("C"))); // 2
    }

    要正确使用Listcontains()indexOf()这些方法,放入的实例必须正确覆写equals()方法,否则,放进去的实例,查找不到。我们之所以能正常放入StringInteger这些对象,是因为Java标准库定义的这些类已经正确实现了equals()方法。

    equals()方法的正确编写方法:

    1. 先确定实例“相等”的逻辑,即哪些字段相等,就认为实例相等;
    2. instanceof判断传入的待比较的Object是不是当前类型,如果是,继续比较,否则,返回false
    3. 对引用类型用Objects.equals()比较,对基本类型直接用==比较。

    使用Objects.equals()比较两个引用类型是否相等的目的是省去了判断null的麻烦。两个引用类型都是null时它们也是相等的。

    如果不调用Listcontains()indexOf()这些方法,那么放入的元素就不需要实现equals()方法。

    public class TestList {

    public static void main(String[] args) {
    List<Person> list = new ArrayList<Person>();
    list.add(new Person("小王", "男", 18));
    list.add(new Person("小明", "男", 25));
    list.add(new Person("小李", "女", 20));
    boolean exist = list.contains(new Person("小明", "男", 25));
    System.out.println(exist ? "查询成功!" : "查询失败!");//查询成功;没有重写equals方法结果返回:查询失败
    }

    }

    class Person {
    String name;
    String sex;
    int age;
    public Person(String name, String sex, int age) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    }

    public boolean equals(Object o){
    if(o instanceof Person){
    Person p = (Person) o;
    return this.name.equals(p.name) && Objects.equals(this.sex,p.sex) && this.age==p.age;
    }
    return false;
    }
    }

    4、Map这种键值(key-value)映射表的数据结构,作用就是能高效通过key快速查找value(元素)。

    如果只是想查询某个key是否存在,可以调用boolean containsKey(K key)方法。

    Map中不存在重复的key,因为放入相同的key,只会把原有的key-value对应的value给替换掉。

    Map来说,要遍历key可以使用for each循环遍历Map实例的keySet()方法返回的Set集合,它包含不重复的key的集合。

    同时遍历keyvalue可以使用for each循环遍历Map对象的entrySet()集合,它包含每一个key-value映射。

    public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("A", 1);
    map.put("B", 2);
    map.put("C", 3);
    for(String key : map.keySet()){
    Integer num = map.get(key);
    System.out.println(num);// 1 2 3
    }

    for(Map.Entry<String,Integer> en :map.entrySet()){
    String aa = en.getKey();
    Integer bb = en.getValue();
    System.out.println(aa+": "+bb);//A:1    B:2  C:3
    }
    }

    5、编写equals和hashCode

    HashMap之所以能根据key直接拿到value,原因是它内部通过空间换时间的方法,用一个大数组存储所有value,并根据key直接计算出value应该存储在哪个索引

     正确使用Map必须保证:

    1. 作为key的对象必须正确覆写equals()方法,相等的两个key实例调用equals()必须返回true

    2. 作为key的对象还必须正确覆写hashCode()方法,且hashCode()方法要严格遵循以下规范:

    •  如果两个对象相等,则两个对象的hashCode()必须相等;
    •  如果两个对象不相等,则两个对象的hashCode()尽量不要相等。

    HashMap初始化时默认的数组大小只有16

    添加超过一定数量的key-value时,HashMap会在内部自动扩容,每次扩容一倍,即长度为16的数组扩展为长度32,相应地,需要重新确定hashCode()计算的索引位置

    HashMap内部的数组长度总是2的n次方

    不同的key具有相同的hashCode()的情况称之为哈希冲突

    要正确使用HashMap,作为key的类必须正确覆写equals()hashCode()方法;

    一个类如果覆写了equals(),就必须覆写hashCode(),并且覆写规则是:

           如果equals()返回true,则hashCode()返回值必须相等;

            如果equals()返回false,则hashCode()返回值尽量不要相等。

    6、TreeMap

    还有一种Map,它在内部会对Key进行排序,这种Map就是SortedMap。注意到SortedMap是接口,它的实现类是TreeMap。

    使用TreeMap时,放入的Key必须实现Comparable接口。StringInteger这些类已经实现了Comparable接口,因此可以直接作为Key使用。作为Value的对象则没有任何要求。

    public static void main(String[] args) {
    //SortedMap内部会对Key进行排序。注意到SortedMap是接口,它的实现类是TreeMap。
    Map<String, String> map = new TreeMap<String, String>();
    map.put("aa", "11");
    map.put("bb", "22");
    map.put("cc", "33");
    map.put("dd", "44");

    //打印结果: 11 22 33 44
    for(String name : map.keySet()){
    String value = map.get(name);
    System.out.print(value+" ");
    }
    }

    7、Set

    最常用的Set实现类是HashSet,实际上,HashSet仅仅是对HashMap的一个简单封装;经常用Set用于去除重复元素

    Set接口并不保证有序,而SortedSet接口则保证元素是有序的:

    • HashSet是无序的,因为它实现了Set接口,并没有实现SortedSet接口;
    • TreeSet是有序的,因为它实现了SortedSet接口。

    8、Queue

    队列(Queue)是一种经常使用的集合。Queue实际上是实现了一个先进先出(FIFO:First In First Out)的有序表。它和List的区别在于,List可以在任意位置添加和删除元素,而Queue只有两个操作:

    • 把元素添加到队列末尾;
    • 从队列头部取出元素。

    队列接口Queue定义了以下几个方法:

    int size():获取队列长度;

    boolean add(E)/boolean offer(E):添加元素到队尾;

    E remove()/E poll():获取队首元素并从队列中删除;

    E element()/E peek():获取队首元素但并不从队列中删除。

    9、栈(Stack)是一种后进先出(LIFO:Last In First Out)的数据结构。

    Stack只有入栈和出栈的操作:

    • 把元素压栈:push(E)
    • 把栈顶的元素“弹出”:pop(E)
    • 取栈顶元素但不弹出:peek(E)

    Stack的作用

    Stack在计算机中使用非常广泛,

         JVM在处理Java方法调用的时候就会通过栈这种数据结构维护方法调用的层次。

                 JVM会创建方法调用栈,每调用一个方法时,先将参数压栈,然后执行对应的方法;当方法返回时,返回值压栈,调用方法通过出栈操作获得方法返回值。

                 因为方法调用栈有容量限制,嵌套调用过多会造成栈溢出,即引发StackOverflowError

          对整数进行进制的转换就可以利用栈

  • 相关阅读:
    时间安排还是很不合理
    ZOJ Problem Set
    ZOJ Problem Set
    ZOJ Problem Set
    ZOJ Problem Set
    还是很水啊!!!
    pragma mark
    IOS应用发布NSLog的如何注释
    设定时间让应用从后台回来是否重新启动应用
    Mac 上SVN上传.a文件
  • 原文地址:https://www.cnblogs.com/wueryuan/p/11857914.html
Copyright © 2020-2023  润新知