zoukankan      html  css  js  c++  java
  • JAVA_基础集合List接口与Set接口(二)

    List接口

    JDK API中List接口的实现类常用的有:ArrayListLinkedListVector

    ArrayList:作为List接口的主要实现类;线程不安全;底层使用Object[] elementData储存。
    LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表储存。
    Vector:作为List接口的古老实现类;线程安全的;效率底;底层使用Object[] elementData储存。

    ArrayList的源码分析:JDK 7
    ArrayList list = new ArrayList();(底层创建了长度是10的Object[]数组elementData
    list.add(123);elementData[0] = new Integer(123);
    list.add(11);(如果此次的添加导致底层elementData数组容量不够,则扩容。)
    默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。

    结论:建议在开发过程中使用带参数的构造器:ArrayList list = new ArrayList(int capacity)

    ArrayList的源码分析:JDK 8

    List接口方法

    void add(int index, Object ele):在index位置插入ele元素 。
    boolean addAll(int index, Collection eles):从index位置开始将eles中 的所有元素添加进来 。
    Object get(int index):获取指定index位置的元素 。
    int indexOf(Object obj):返回obj在集合中首次出现的位置 。
    int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 。
    Object remove(int index):移除指定index位置的元素,并返回此元素 。
    Object set(int index, Object ele):设置指定index位置的元素为ele
    List subList(int fromIndex, int toIndex):返回从fromIndextoIndex 位置的子集合。

    public void test() {
            ArrayList list = new ArrayList();
            list.add(132);
            list.add(456);
            list.add("AA");
            list.add(new Person("Tom", 12));
            System.out.println(list);// [132, 456, AA, Person{name='Tom', age=12}]
            list.add(1,"BB");
            System.out.println(list);// [132, BB, 456, AA, Person{name='Tom', age=12}]
            List list1 = Arrays.asList(1, 2, 3);
            list.addAll(list1);
            System.out.println(list.size());// 8
            System.out.println(list.get(1));// BBjava
        }
    public void test1() {
            ArrayList list = new ArrayList();
            list.add(132);
            list.add(456);
            list.add("AA");
            list.add(new Person("Tom", 12));
            list.add("456");
            int i = list.indexOf(456);
            System.out.println(i);// 1
            System.out.println(list.lastIndexOf("AA"));// 2
            Object remove = list.remove(0);
            System.out.println(remove);// 132
            System.out.println(list);// [456, AA, Person{name='Tom', age=12}]
            Object cc = list.set(1, "CC");
            System.out.println(cc);// AA
            System.out.println(list);// [456, CC, Person{name='Tom', age=12}]
            List subList = list.subList(2, 4);
            System.out.println(subList);// [Person{name='Tom', age=12}, 456]
            System.out.println(list);// [456, CC, Person{name='Tom', age=12}, 456]
        }
    public void test3() {
            ArrayList list = new ArrayList();
            list.add(123);
            list.add(456);
            list.add("AA");
            list.add("BB");
            // 方式一:Iterator迭代器方式循环遍历
            Iterator iterator = list.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
            System.out.println("*******************");
            // 方式二:forEach增强循环遍历
            for (Object obj : list) {
                System.out.println(obj);
            }
            System.out.println("*******************");
            // 方式三:普通for循环遍历
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
        }
    

    Set接口

    Set接口:储存无序的、不可重复的数据。
    HashSet:作为Set接口的主要实现类;线程不安全的;可以储存null值。
    LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历。
    优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
    TreeSet:可以按照添加对象的指定属性,进行排序。

    一、储存无序、不可重复:(以HashSet为例说明)

    1. Set无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加。而是根据数据的哈希值决定的。
    2. Set不可重复性:保证添加的元素按照equals()判断时,不能返回true。即:相同的元素只能添加一个。

    二、添加元素的过程:(以HashSet为例说明)

    1. 我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法出生在HashSet底层数组中的位置(即为:索引位置)。
      数组此位置上是否已经有元素:
      如果有此位置上没有其它元素,则元素a添加成功。→情况1
      如果此位置上有其它元素B(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
      如果hash值不相同,则元素a添加成功。→情况2
      如果hash值相同,进而需要调用元素a所在类的equlas()方法:
      equlas()返回true,元素a添加失败。
      equlas()返回false,则元素a添加成功。→情况3
      对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上数据以链表的方式储存。
      JDK 7:元素a放到数组中,指向原来的元素。
      JDK 8:原来的元素在数组中,指向元素a。
      总结:七上八下

      HashSet底层:数组+链表的结构。

      要求:向Set中添加的数据,其所在的类一定要重写hashCode()equlas()
      要求:重写的hashCode()equlas()尽可能的保持一致性:相等的对象必须具有相等的散列码(hash值)。

      public void test() {
              Set set = new HashSet();
              set.add(456);
              set.add(123);
              set.add("AA");
              set.add("CC");
              set.add(new User("Tom",20));
              set.add(new User("Tom",20));
              set.add(new User("Jerry",19));
              set.add("DD");
              Iterator iterator = set.iterator();
              while(iterator.hasNext()) {
                  System.out.println(iterator.next());
              }
          }
      
      public class User {
          private String name;
          private int age;
      	...
          @Override
          public String toString() {
      		...
          }
          @Override
          public boolean equals(Object o) {
              System.out.println("User equals()...");
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
      
              User user = (User) o;
      
              if (age != user.age) return false;
              return name != null ? name.equals(user.name) : user.name == null;
          }
          @Override
          public int hashCode() {
              int result = name != null ? name.hashCode() : 0;
              result = 31 * result + age;
              return result;
          }
      }
      

    三、LinkedHashSet的使用

    LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据。
    ​ 优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet

        public void test2() {
            Set set = new LinkedHashSet();
            set.add(456);
            set.add(123);
            set.add("AA");
            set.add("CC");
            set.add(new User("Tom",20));
            set.add(new User("Tom",20));
            set.add(new User("Jerry",19));
            set.add("DD");
    
            Iterator iterator = set.iterator();
            while(iterator.hasNext()) {
                System.out.println(iterator.next());
            }
        }
    

    四、TreeSet的使用

    1. TreeSet中添加的数据,要求是相同类的对象。
      失败:不能添加不同类的对象

      set.add(123);
      set.add("AA");
      set.add(new User("Tom",20));
      
    2. 两种排序方式:自然排序(实现Comparable接口) 和 定制排序(Comparator

      自然排序中,比较两个对象是否行同的标准为:compareTo()返回0,不再是equlas()

      public void test1() {
              TreeSet set = new TreeSet();
              // 举例一:
      //        set.add(123);
      //        set.add(456);
      //        set.add(-487);
      //        set.add(9);
              // 举例二:
      //        set.add("AA");
      //        set.add("DD");
      //        set.add("BB");
      //        set.add("ABC");
              // 举例三:
              set.add(new User("Tom",22));
              set.add(new User("Jerry",22));
              set.add(new User("Jim",20));
              set.add(new User("Mike",54));
              set.add(new User("Jack",58));
              set.add(new User("Jack",20));
              Iterator iterator = set.iterator();
              while (iterator.hasNext()) {
                  System.out.println(iterator.next());
              }
          }
      
      public class User implements Comparable {
          private String name;
          private int age;
          @Override
          public String toString() {...}
          @Override
          public boolean equals(Object o) {...}
          @Override
          public int hashCode() {...}
          // 按照姓名从小到大排序,年龄从小到大排序
          @Override
          public int compareTo(Object o) {
              if (o instanceof User) {
                  User user = (User) o;
                  int compare = user.name.compareTo(this.name);
                  if (compare != 0) {
                      return compare;
                  }else {
                      return Integer.compare(this.age,user.age);
                  }
              }else {
                  throw new RuntimeException("当前传递的类型不匹配");
              }
          }
      }
      

      定制排序中,比较两个对象是否行同的标准为:compare()返回0,不再是equlas()

      public void test2() {
              Comparator comparator = new Comparator() {
                  // 按照年龄从小到大排序
                  @Override
                  public int compare(Object o1, Object o2) {
                      if (o1 instanceof User && o2 instanceof User) {
                          User user1 = (User) o1;
                          User user2 = (User) o2;
                          return Integer.compare(user1.getAge(),user2.getAge());
                      }else {
                          throw new RuntimeException("传入的类型不匹配");
                      }
                  }
              };
              TreeSet set = new TreeSet(comparator);
              set.add(new User("Tom",22));
              set.add(new User("Jerry",21));
              set.add(new User("Jim",20));
              set.add(new User("Mike",54));
              set.add(new User("Mary",54));
              set.add(new User("Jack",58));
              set.add(new User("Jack",20));
              Iterator iterator = set.iterator();
              while (iterator.hasNext()) {
                  System.out.println(iterator.next());
              }
          }
      
  • 相关阅读:
    object-c iOS 教程 git for mac
    mac Git本地服务器配置
    [转]XCode中修改缺省公司名称/开发人员名称
    IOS------Warning
    Linux---CentOS 定时运行脚本配置练手
    微信公众号一些错误的原因错误代码41001
    微信支付的一些新的经验总结
    关于THINKPHP5模型关联的初步理解
    写下thinkphp5和thinkphp3.2的不同
    练手THINKPHP5过程和bootstrap3.3.7
  • 原文地址:https://www.cnblogs.com/BeautifulGirl230/p/14228246.html
Copyright © 2011-2022 走看看