zoukankan      html  css  js  c++  java
  • Java集合框架之一

      

    Collection表示一组对象,它是集中 ,收集的意思,就是把一些数据收集起来。

    Java集合大致可分为Set、List、Queue和Map

    Set:代表无序、不可重复的集合;

    List:代表有序、重复的集合;

    ArrayList:底层实现是数组,线程不安全,效率高。所以,查询快。修改、插入、删除慢。

    LinkedList:底层实现是链表,线程不安全,效率高。所以,查询慢。修改、插入、删除快。

    Vector:底层实现是数组,线程安全,效率低。所以,查询快。修改、插入、删除慢。

    List有三个儿子,我们到底使用谁呢?

    看需求(情况)。

     

    要安全吗?

    要:Vector(即使要安全,也不用这个了,后面有替代的)

    不要:ArrayList或者LinkedList

    查询多:ArrayList

    增删多:LinkedList

     

    如果你什么都不懂,就用ArrayList。

     

    Map:代表具有映射关系的集合;

    Queue:代表一种队列集合的思想。

     

    1:对象数组(掌握)

    (1)数组既可以存储基本数据类型,也可以存储引用类型。它存储引用类型的时候的数组就叫对象数组。

    (2)案例:

    用数组存储5个学生对象,并遍历数组。

     

    2:集合(Collection)(掌握)

    (1)集合的由来?

    我们学习的是Java -- 面向对象 -- 操作很多对象 -- 存储 -- 容器(数组和StringBuffer) -- 数组

    而数组的长度固定,所以不适合做变化的需求,Java就提供了集合供我们使用。

    (2)集合和数组的区别?

    A:长度区别

    数组固定

    集合可变

    B:内容区别

    数组可以是基本类型,也可以是引用类型

    集合只能是引用类型

    C:元素内容

    数组只能存储同一种类型

    集合可以存储不同类型(其实集合一般存储的也是同一种类型)

    (3)集合的继承体系结构?

    由于需求不同,Java就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,

    我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。

     

    Collection

    |--List

    |--ArrayList

    |--Vector

    |--LinkedList

    |--Set

    |--HashSet

    |--TreeSet

    (4)Collection的功能概述(自己补齐)

    A:添加功能

    B:删除功能

    C:判断功能

    D:获取功能

    E:长度功能

    F:交集(了解)

    G:把集合转数组(了解)

    (5)Collection集合的遍历

    A:把集合转数组(了解)

    B:迭代器(集合专用方式)

    (6)迭代器

    A:是集合的获取元素的方式。

    B:是依赖于集合而存在的。

    C:迭代器的原理和源码。

    a:为什么定义为了一个接口而不是实现类?

    b:看了看迭代器的内部类实现。

    (7)Collection集合的案例(遍历方式 迭代器)

    集合的操作步骤:

    A:创建集合对象

    B:创建元素对象

    C:把元素添加到集合

    D:遍历集合

     

    A:存储字符串并遍历

    import java.util.Collection;
    
    import java.util.ArrayList;
    
    import java.util.Iterator;
    
     
    
    public class CollectionDemo {
    
        public static void main(String[] args) {
    
            //创建集合对象
    
            Collection c = new ArrayList();
    
     
    
            //创建并添加元素
    
            c.add("hello");
    
            c.add("world");
    
            c.add("java");
    
     
    
            //遍历集合
    
            Iterator it = c.iterator();
    
            while(it.hasNext()) {
    
                String s =(String) it.next();
    
                System.out.println(s);
    
            }
    
        }
    
    }
    
     

    B:存储自定义对象并遍历

    public class Student {
    
        private String name;
    
        private int age;
    
     
    
        public Student(){}
    
     
    
        public Student(String name,int age) {
    
            this.name = name;
    
            this.age = age;
    
        }
    
     
    
        //getXxx()/setXxx()
    
    }
    
     
    
    import java.util.Collection;
    
    import java.util.ArrayList;
    
    import java.util.Iterator;
    
     
    
    public class StudentDemo {
    
        public static void main(String[] args) {
    
            //创建集合对象
    
            Collection c = new ArrayList();
    
     
    
            //创建学生对象
    
            Student s1 = new Student("林青霞",27);
    
            Student s2 = new Student("风清扬",30);
    
            Student s3 = new Student("刘意",30);
    
            Student s4 = new Student("武鑫",25);
        
            Student s5 = new Student("刘晓曲",16);
    
     
    
            //添加元素
    
            c.add(s1);
    
            c.add(s2);
    
            c.add(s3);
    
            c.add(s4);
    
            c.add(s5);
    
     
    
            //遍历集合
    
            Iterator it = c.iterator();
    
            while(it.hasNext()) {
    
                Student s = (Student)it.next();
    
                System.out.println(s.getName()+"---"+s.getAge());
    
           }
    
        }
    
    }
    
     

    3:集合(List)(掌握)

    (1)List是Collection的子接口

    特点:有序(存储顺序和取出顺序一致),可重复。

    (2)List的特有功能:(自己补齐)

    A:添加功能

    B:删除功能

    C:获取功能

    D:迭代器功能

    E:修改功能

    (3)List集合的特有遍历功能

    A:由size()和get()结合。

    B:代码演示

    //创建集合对象

    List list = new ArrayList();

    //创建并添加元素

    list.add("hello");

    list.add("world");

    list.add("java");

     

    //遍历集合

    Iterator it = list.iterator();

    while(it.hasNext()) {

    String s =(String) it.next();

    System.out.println(s);

    }

    System.out.println("----------");

     

    for(int x=0; x<list.size(); x++) {

    String s =(String) list.get(x);

    System.out.println(s);

    }

     

    (4)列表迭代器的特有功能;(了解)

    可以逆向遍历,但是要先正向遍历,所以无意义,基本不使用。

    (5)并发修改异常

    A:出现的现象

    迭代器遍历集合,集合修改集合元素

    B:原因

    迭代器是依赖于集合的,而集合的改变迭代器并不知道。

    C:解决方案

    a:迭代器遍历,迭代器修改(ListIterator)

    元素添加在刚才迭代的位置

    b:集合遍历,集合修改(size()和get())

    元素添加在集合的末尾

    (6)常见数据结构

    A:栈 先进后出

     堆栈,采用该结构的集合,对元素的存取有如下的特点:

     先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去 的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。  栈的入口、出口的都是栈的顶端位置 

      压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。 

      弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

    B:队列 先进先出

    队列,采用该结构的集合,对元素的存取有如下的特点:

    先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,安检。排成一列,每个人依次检查,只有前面的人全部检查完毕后,才能排到当前的人进行检查。 

     队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口。

    C:数组 查询快,增删慢

     数组,采用该结构的集合,对元素的存取有如下的特点:

    查找元素快:通过索引,可以快速访问指定位置的元素

    增删元素慢:

     指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。如下图 

    指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。如下图

    D:链表 查询慢,增删快

    链表,采用该结构的集合,对元素的存取有如下的特点:

     多个节点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了。

    查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素。

     增删元素快:

    增加元素:操作如左图,只需要修改连接下个元素的地址即可。

     删除元素:操作如右图,只需要修改连接下个元素的地址即可。

    (7)ArrayList集合

    ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。

    许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。

    (8)LinkedList集合

    LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。如下图

    LinkedList是List的子类,List中的方法LinkedList都是可以使用,这里就不做详细介绍,我们只需要了解LinkedList的特有方法即可。在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。

    方法演示:   

      LinkedList<String> link = new LinkedList<String>();
    
            //添加元素
    
            link.addFirst("abc1");
    
            link.addFirst("abc2");
    
            link.addFirst("abc3");
    
            //获取元素
    
            System.out.println(link.getFirst());
    
            System.out.println(link.getLast());
    
            //删除元素
    
            System.out.println(link.removeFirst());
    
            System.out.println(link.removeLast());
    
           
    
            while(!link.isEmpty()){ //判断集合是否为空
    
               System.out.println(link.pop()); //弹出集合中的栈顶元素
    
           }

    (9)Vector集合

      Vector集合数据存储的结构是数组结构,为JDK中最早提供的集合。Vector中提供了一个独特的取出方式,就是枚举Enumeration,它其实就是早期的迭代器。此接口Enumeration的功能与 Iterator 接口的功能是类似的。Vector集合已被ArrayList替代。枚举Enumeration已被迭代器Iterator替代。

     Vector常见的方法:

     

     Enumeration枚举常见的方法:

     Vector集合对ArrayList集合使用的对比

    (10)List的子类特点(面试题)

    ArrayList

    底层数据结构是数组,查询快,增删慢。

    线程不安全,效率高。

    Vector

    底层数据结构是数组,查询快,增删慢。

    线程安全,效率低。

    LinkedList

    底层数据结构是链表,查询慢,增删快。

    线程不安全,效率高。

     

    到底使用谁呢?看需求?

    分析:

    要安全吗?

    要:Vector(即使要,也不使用这个,后面再说)

    不要:ArrayList或者LinkedList

    查询多;ArrayList

    增删多:LinkedList

     

    什么都不知道,就用ArrayList。

    (11)List集合的案例(遍历方式 迭代器和普通for)

    A:存储字符串并遍历

    B:存储自定义对象并遍历

    4:集合(Set)(掌握)

    (1)Set接口介绍

    学习Collection接口时,记得Collection中可以存放重复元素,也可以不存放重复元素,那么我们知道List中是可以存放重复元素的。那么不重复元素给哪里存放呢?那就是Set接口,它里面的集合,所存储的元素就是不重复的。

    (2)HashSet集合

      查阅HashSet集合的API介绍:此类实现Set接口,由哈希表支持(实际上是一个 HashMap集合)。HashSet集合不能保证的迭代顺序与元素存储顺序相同。

    HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依赖于:hashCode()与equals()方法。

    (3)HashSet集合存储数据的结构(哈希表)

      什么是哈希表呢?

      哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会根据这些对象的特有数据结合相应的算法,计算出这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组,即就是哈希表。

      当向哈希表中存放元素时,需要根据元素的特有数据结合相应的算法,这个算法其实就是Object类中的hashCode方法。由于任何对象都是Object类的子类,所以任何对象有拥有这个方法。即就是在给哈希表中存放对象时,会调用对象的hashCode方法,算出对象在表中的存放位置,这里需要注意,如果两个对象hashCode方法算出结果一样,这样现象称为哈希冲突,这时会调用对象的equals方法,比较这两个对象是不是同一个对象,如果equals方法返回的是true,那么就不会把第二个对象存放在哈希表中,如果返回的是false,就会把这个值存放在哈希表中。

      总结:保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。

     面试题:

      两个对象 Person p1 p2
    * 问题: 如果两个对象的哈希值相同 p1.hashCode()==p2.hashCode()
    * 两个对象的equals一定返回true吗 p1.equals(p2) 一定是true吗
    * 正确答案:不一定
    *
    * 如果两个对象的equals方法返回true,p1.equals(p2)==true
    * 两个对象的哈希值一定相同吗
    * 正确答案: 一定

    (4)HashSet存储API中的类型元素

      给HashSet中存储JavaAPI中提供的类型元素时,不需要重写元素的hashCode和equals方法,因为这两个方法,在JavaAPI的每个类中已经重写完毕,如String类、Integer类等。

     创建HashSet集合,存储String对象。

    public class HashSetDemo {
        public static void main(String[] args) {
    
            //创建HashSet对象
            HashSet<String> hs = new HashSet<String>();
            //给集合中添加自定义对象
            hs.add("zhangsan");
            hs.add("lisi");
            hs.add("wangwu");
            hs.add("zhangsan");
            //取出集合中的每个元素
            Iterator<String> it = hs.iterator();
            while(it.hasNext()){
               String s = it.next();
               System.out.println(s);
            }
    
        }
    
    }

    输出结果如下,说明集合中不能存储重复元素:

    wangwu

    lisi

    zhangsan

     

    (5) HashSet存储自定义类型元素

      给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一

    创建自定义对象Student

    public class Student {
        private String name;
        private int age;
        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 instanceof Student)){
                System.out.println("类型错误");
                return false;
            }
            Student other = (Student) obj;
            return this.age ==  other.age && this.name.equals(other.name);
        }
    }

     创建HashSet集合,存储Student对象。

    public class HashSetDemo {
        public static void main(String[] args) {
            //创建HashSet对象
            HashSet hs = new HashSet();
            //给集合中添加自定义对象
            hs.add(new Student("zhangsan",21));
            hs.add(new Student("lisi",22));
            hs.add(new Student("wangwu",23));
            hs.add(new Student("zhangsan",21));
            //取出集合中的每个元素
            Iterator it = hs.iterator();
            while(it.hasNext()){
                Student s = (Student)it.next();
                System.out.println(s);
            }
        }
    }

    输出结果如下,说明集合中不能存储重复元素:

    Student [name=lisi, age=22]

    Student [name=zhangsan, age=21]

    Student [name=wangwu, age=23]

    (6) LinkedHashSet介绍

      我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?

    在HashSet下面有一个子类LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

    演示代码如下:

    public class LinkedHashSetDemo {
        public static void main(String[] args) {
            Set<String> set = new LinkedHashSet<String>();
            set.add("bbb");
            set.add("aaa");
            set.add("abc");
            set.add("bbc");
    Iterator it = set.iterator();
            while (it.hasNext()) {
                System.out.println(it.next());
            }
        }
    }

    输出结果如下,LinkedHashSet集合保证元素的存入和取出的顺序:

    bbb

    aaa

    abc

    bbc

    (7) 判断集合元素唯一的原理

     ArrayList的contains方法判断元素是否重复原理

      ArrayList的contains方法会使用调用方法时,传入的元素的equals方法依次与集合中的旧元素所比较,从而根据返回的布尔值判断是否有重复元素。此时,当ArrayList存放自定义类型时,由于自定义类型在未重写equals方法前,判断是否重复的依据是地址值,所以如果想根据内容判断是否为重复元素,需要重写元素的equals方法。

     HashSet的add/contains等方法判断元素是否重复原理

    Set集合不能存放重复元素,其添加方法在添加时会判断是否有重复元素,有重复不添加,没重复则添加。

    HashSet集合由于是无序的,其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:

    先判断新元素与集合内已经有的旧元素的HashCode值

    l  如果不同,说明是不同元素,添加到集合。

    l  如果相同,再判断equals比较结果。返回true则相同元素;返回false则不同元素,添加到集合。

    所以,使用HashSet存储自定义类型,如果没有重写该类的hashCode与equals方法,则判断重复时,使用的是地址值,如果想通过内容比较元素是否相同,需要重写该元素类的hashcode与equals方法。

  • 相关阅读:
    hinge loss
    KL散度
    pygame 学习
    pytorch 反向传播
    在线画数学函数图
    recover deleted files
    98个关键点的人脸
    Pytorch详解BCELoss和BCEWithLogitsLoss
    one hot vector
    Effective C++
  • 原文地址:https://www.cnblogs.com/guodong-wang/p/7196914.html
Copyright © 2011-2022 走看看