zoukankan      html  css  js  c++  java
  • Java集合

    一、hashCode与equals

    这两个方法来自于Object类,所以每个类型都会自动继承这2个方法.这2个方法本质上并没有任何关系,彼此独立,而且这两个方法在脱离集合的环境下也是可以使用的.但这两个方法的理解对于更好的使用集合是必不可少的.

    1.equals

    Object类对equals的默认实现如下

    public boolean equals(Object obj) {
       return (this == obj);
    }

    这种实现只是表示引用相等,字符串对这个方法进行了重写,用于判断两个字符串的值是否相等.比如下面的代码

    String s = new String("abc");
    String s2 = new String("abc");
    System.out.println(s==s2); //false
    System.out.println(s.equals(s2));//true

    通常重写 equals() 方法时,要重写 hashCode() 方法,以表示:如果两个对象是 equals 的,那么其 hashCode() 值也应该一样。

    2.hashCode

    hashCode方法主要用来支持java 集合框架中的Hash相关的集合,比如HashMap,HashSet等.

    在Object类中hashCode的实现如下:

    public native int hashCode();

    这个是一个本地方法,其默认实现返回的hashCode是对象的内存地址进行hash算法得出的值.在hashCode的注释中,对hashCode的实现要求如下:

    • 任何时候,反复调用同一个对象的hashCode方法,返回的值要一样

    • 如果两个对象equals相等,那么其hashCode应该要一样

    • 如果两个对象非equals相等,其hashCode可以一样,但不强制要求.

     

    Hash 算法又叫散列算法,由 Hash(人名)首先提出。

    Hash 算法:把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。

    为什么要用 hash 算法?

    Hash 算法的输出值是固定长度的,该值可以被用来作为内存地址。 这样取的时候,就可以通过计算其 hash 值来获取所在内存存储单元的地址,而快速的读取其存储的内容。

     

    二、Comparable 与Comparator

    jdk中的Comparable接口与Comparator接口都与排序有关,当对象放入到一些有序的集合时会对对象的排序性有要求,所以有必要了解这2个接口

    1.Comparable

    若一个类实现了Comparable接口,就意味着“该类支持排序” 此接口是jdk 1.2推出的,它的代码如下:

    //java.lang jdk 1.2就有
    public interface Comparable<T> {
     public int compareTo(T o);
    }

    当一个类实现了此接口时,通常是此实现类与compareTo方法传递过来的参数进行比较,比较的规则是当自身小于传递过来的对象时返回负数,相等就返回0,大于就返回正数.比如下面的代码:

    class Student implements Comparable<Student>{   
     String name;  
     int age;  
     
     Student(String name,int age){  
       this.name=name;  
       this.age=age;  
    }  
     public int compareTo(Student st){  
       if(age==st.age)  
      return 0;  
       else if(age>st.age)  
      return 1;  
       else  
      return -1;  
    }  
    }  

    实现了Comparable接口后,此对象放入到集合中就可以对集合中的元素进行排序了,比如下面的代码

    ArrayList<Student> al=new ArrayList<Student>();  
    al.add(new Student("a",23));  
    al.add(new Student("b",27));  
    al.add(new Student("c",21));  
     
    Collections.sort(al);  
    for(Student st:al){  
    System.out.println(st.name+" "+st.age);  
    }

    输出结构为:

    c 21
    a 23
    b 27

    上面的结果可以看出以升序排序,如果想改为降序排序,必须修改Student类中的实现,把返回1的地方改为返回-1,返回-1的地方改为1.也就是说想改变排序规则必须修改源代码.还有一个不足之处就是只支持固定的排序规则,比如现在的实现只支持按年龄排序,不支持按名字排序.基于这种情况就需要使用Comparator来完成这样的功能.

    2.Comparator

    此接口在java.util包下,用来实现两个对象之间比较功能的.并且也并不要求被比较的对象实现某个接口.此接口的核心比较代码如下:

    public interface Comparator<T> {
     int compare(T o1, T o2);
    }

    compare方法的比较逻辑与Comparable接口的compareTo方法类似,当第一个参数小于第二个参数时返回负数,相等返回0,大于返回正数.比如下面的代码实现了对Student类的年龄的比较

    class AgeComparator implements Comparator<Student>{  
     public int compare(Student s1,Student s2){  
       if(s1.age==s2.age)  
      return 0;  
       else if(s1.age>s2.age)  
      return 1;  
       else  
      return -1;  
    }  
    }  

    下面的代码实现了对名字的比较

    class NameComparator implements Comparator<Student>{  
     public int compare(Student s1,Student s2){
       //String类本身实现了Comparable接口
       return s1.name.compareTo(s2.name);  
    }  
    }  

    使用方式如下:

    ArrayList<Student> al=new ArrayList<Student>();  
    al.add(new Student("a",23));  
    al.add(new Student("b",27));  
    al.add(new Student("c",21));  

    System.out.println("依据名字进行比较");
    Collections.sort(al,new NameComparator());  
    for(Student st:al){  
    System.out.println(st.name+" "+st.age);  
    }

    System.out.println("依据年龄进行比较");
    Collections.sort(al,new AgeComparator());  
    for(Student st:al){  
    System.out.println(st.name+" "+st.age);  
    }

    最终输出的结果为

    依据名字进行比较
    a 23
    b 27
    c 21

    依据年龄进行比较
    c 21
    a 23
    b 27


    三、简介

    数组主要存放的是同类型的数据,其最大的一个缺点就是其大小不能动态调整,这对于一些预先不确定数据量大小的情况无法应付,所以java推出了集合框架.

     

    四、集合框架图

    集合框架是存储于操纵一组对象的统一架构,它由一系列的接口和实现类组成,这些类型包含了如何存储对象以及操作这些数据的算法,比如排序算法.

    整个java集合框架由Collection接口与Map接口代表.当然有一种说法认为java的集合框架只包含Collection接口体系,不包含Map接口代表的体系.下面是包含Collection与Map的整个架构:

    下图是Collection接口代表的核心体系架构

    image-20190718192054677

    五、List

    List接口代表线性结构的集合,它以线性的方式来存储数据,并且允许存储重复的数据.此接口的主要实现类如下:

    •  ArrayList

    •  LinkedList

    •  Vector

    •  Stack

    1.ArrayList

    ArrayList是一个内部用数组实现List接口的集合类.

    ArrayList<String> list=new ArrayList<String>();
    list.add("a");
    list.add("b");  

    在实例化集合对象时最好指定初始容量,容量大小尽量与预计存放的数据量差不多,值建议用2的n次方.这样可以减少集合频繁扩容造成的性能损失.如果不指定容量大小,ArrayList默认的大小为10.

    ArrayList<String> list=new ArrayList<String>(4);

    ArrayList由于内部是数组实现的集合,它支持通过索引来取得集合中的数据,比如

    list.get(0)

    通过索引取值的方式,其时间复杂度是个常量值.性能很高.但ArrayList集合删除数据或者往中间插入数据性能不高,因为其要逻动数据.

    在遍历集合时,尽量不要进行集合的修改操作,比如删除元素.这非常容易产生bug,比如下面的代码:

    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");

    for (String item : list) {
     if ("2".equals(item)) { //把这里的2改为1试试
       list.remove(item);
    }
    }

    for (String item : list) {
     System.out.println(item);
    }

     

    2.LinkedList

    LinkedList用双链表来实现List接口,因而此类型往里面插入,删除速度性能较高.但通过索引取值的时间复杂度是O(n),性能不高.基本使用方法如下:

    LinkedList<String> al=new LinkedList<String>();  
    al.add("a");  
    al.add("b");  

     

    六、Iterable与Iterator

    实现了此接口的类型支持foreach循环,由于Collection接口的父类型就是Iterable,所以所有的Collection都支持foreach循环.

    此接口的主要方法为Iterator<T> iterator()此Iterator就是真正完成迭代功能的接口.Iterator接口的主要成员如下:

    • hasNext():检查迭代器是否还有元素

    • next():获取迭代器的下一个元素.

    • remove:删除一个元素.

    迭代器(Iterator)中完成foreach循环的方法只有hasNext与next,remove主要用来完成在迭代的时候删除元素.

    ArrayList<String> list=new ArrayList<String>();
    list.add("a");
    list.add("b");

    Iterator it=list.iterator();  
    while(it.hasNext()){  
    System.out.println(it.next());  
    }

    在迭代集合的时候,如果要删除元素建议用迭代器实现.

     

    七、Map

    Map类型是一种键值对类型,键和值是一一映射(map)的,每一个键值对称之为一个条目(Entry).Map包含唯一的键.Map集合非常适合依据键来搜索,更新,删除元素的情况.map的体系结构如下:

    image-20190718210958036

    从上图中看出Map的类型主要有以下几个:

    • HashMap:它不维护插入元素的顺序(order)

    • LinkedHashMap:它维护插入的顺序

    • TreeMap:它支持排序.默认是升序排列Map中的元素.

    Map不允许有重复的键,但值允许重复.HashMap与LinkedHashMap允许键与值存放null值,但TreeMap的键与值都不允许null值.

    1.HashMap

    HashMap 首先初始化一块内存(数组)。把内存划分为一个一个的存储空间(bucket),每一个存储空间都有一个地址与其对应。但是,一个存储空间,不限于只存一对键值对(HashMap 使用 LinkedList 存储多个具有相同 hashCode 的键值对。新加的放在最前).基本使用如下:

    Map<Integer,String> map=new HashMap<Integer,String>();    
    map.put(1,"a");  
    map.put(5,"b");
    map.put(2,"b");
    map.get(1) //去值,结果为:a

     

    2.存值

    存放值的时候会依据键的hasCode值来确定存放的槽位(backet),如果此槽位没内容,直接存放.如果此槽位有内容就比较槽位已有对象与即将插入对象的相等性(equals方式比较),相等的话就覆盖,不相等就直接插入此槽位的linkedList里面去.

    3.取值

    使用一个object作为键来取HashMap 中对应的值时,HashMap 的工作方法是:通过传入的键的 hashcode() 在Map中找槽位,当找到这个槽位后再通过 equals() 来比较传入的object和地址中的object(s)(可能是多个),结果为 true 就取出 value。

    4.遍历

    HashMap可以分别对其键,值,键值对进行遍历,效率最高的遍历方式是键值对的遍历方式.因为只遍历键来取值的话其实是把集合遍历了2次

    //键的遍历
    for(Integer k: map.keySet()) {
     System.out.println(k);
    }
    //值的遍历
    for(String v:map.values()) {
     System.out.println(v);
    }
    // 键值对遍历
    for(Map.Entry<Integer,String> entry: map.entrySet()) {
     System.out.println("key:" + entry.getKey() + " value: " + entry.getValue());
    }

    5.对象作为key

    假设有这么一个类想作为Map集合中的键,在存放到集合中的时候需要注意处理其hashCode与equals方法的重写问题.

    public class Person {
    private int id;
    public Person(int id) {
    this.id = id;
    }
    }

    使用的代码如下,最终集合中的数量为2.因为p1与p2是两个不同的对象.

    Map<Person,String> map = new HashMap<>(4);
    Person p1 = new Person(1);
    Person p2 = new Person(1);
    map.put(p1, "a");
    map.put(p2,"b");
    System.out.println(map.size());//输出的结果是2

    如果你基于业务的需要觉得两个Person对象的id是一样的话,应该是相等的,那么你此时就应该重写equals方法.按照规范,重写equals方法时应该也相应的重写hashCode方法.利用eclipse帮我们生成的equals与hashCode方法实现,最终person类的代码如下:

    public class Person {
    private int id;
    public Person(int id) {
    this.id = id;
    }
    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + id;
    return result;
    }
    @Override
    public boolean equals(Object obj) {
    if (this == obj)
    return true;
    if (obj == null)
    return false;
    if (getClass() != obj.getClass())
    return false;
    Person other = (Person) obj;
    if (id != other.id)
    return false;
    return true;
    }
    }

    再次运行上面的代码会发现最终集合中的数量是1.

    八、TreeMap

    内部用树结构实现的一个有序的Map类型.其排序是依据键来进行排序的,并且要求所有的键实现了Comparable接口

    Map<Integer,String> map=new TreeMap<Integer,String>();    
    map.put(1,"a");  
    map.put(5,"b");
    map.put(2,"b");
    for(Map.Entry<Integer,String> entry: map.entrySet()) {
     System.out.println("key:" + entry.getKey() + " value: " + entry.getValue());
    }

    输出的结果为:

    key:1 value: a
    key:2 value: b
    key:5 value: b

    如果存放的键的类型没有实现Comparable接口会报ClassCastException.键的类型必须实现了Comparable接口.代码如下:

    public class Person implements Comparable<Integer> {
    private int id;
    public Person(int id) {
    this.id = id;
    }
     public int getId() {
    return this.id;
    }
    // 省略hashCod与equals方法的实现,与上面的一样.
    @Override
    public int compareTo(Person p) {
    if(this.id < p.getId()) {
    return -1;
    }else if(this.id == p.getId()) {
    return 0;
    }else {
    return 1;
    }
    }
    }

    使用此类的代码如下,最终输出的结果为1,3,10的升序排列

    Map<Person,String> map = new TreeMap<>();
    Person p1 = new Person(10);
    Person p2 = new Person(1);
    Person p3 = new Person(3);
    map.put(p1, "a");
    map.put(p2,"b");
    map.put(p3,"c");
    for(Map.Entry<Person,String> entry:map.entrySet()) {
     System.out.println(entry.getKey().getId());
    }

     

    九、Set

    它主要用来存放不重复的数据,可以存放null值,但只能存放一个null值.set集合是无序的,主要实现类有HashSet,LinkedHashSet,TreeSet.可以利用Set元素唯一的特性快速对一个集合进行去重的操作.

    1.HashSet

    内部用一个hash map集合来存放数据,存放数据时利用对象的hashcode来确定是否存在重复.基本使用如下:

    HashSet<String> set=new HashSet<String>();  
    set.add("a");  
    set.add("b");
    set.add("b");  // 总数量为2

    2.TreeSet

    此集合是有序的.基本使用方法如下:

    HashSet<String> set=new TreeSet<String>();  
    set.add("a");  
    set.add("b");
    set.add("c"); // 总数量为2

     

    十、Stack

    栈是一种先进后出的数据结构,java集合中用Stack类实现栈这种数据结构,此类是Vector的子类,并添加了push,pop,peek等栈专有的方法.其基本使用方法如下:

    Stack<String> stack = new Stack<String>();  
    stack.push("a");  
    stack.push("b");  
    stack.pop();

     

    十一、Queue

    队列是一种先进先出的数据结构,在集合框架中用Queue接口代表队列.常见的实现类有:

    •  LinkedList

    •  PriorityQueue

    •  ArrayDeque()

    LinkedList

     

    LinkedList<String> ll = new LinkedList<>();
    ll.addFirst("a");
    ll.addFirst("b");
    String value = ll.removeLast();// value为a

     

    十二、总结

    image-20200506113802586

    image-20200506113837667

    image-20200506113918505

    image-20200506141701857

    十三、Collections

    此类是java.util包下的一个工具类,不能实例化,此类包含的都是一些静态的方法,用来操作集合或者返回集合.此类包含的方法主要有以下一些作用

    •  排序

    •  搜索

    •  往集合填充,拷贝数据

    •  求取集合的最大值最小值

    •  获取集合的只读视图

    •  获取线程安全的同步集合

    •  获取空的集合

    •  获取检查集合

    下面的代码演示了Collections类的一些常见用法

    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(4);
    list.add(3);
    list.add(1);
    list.add(2);
    list.add(3);
    // 排序
    Collections.sort(list);
    // 二分查找的前提是排序好的元素
    System.out.println( Collections.binarySearch( list , 8 ) );  // 找不到返回-1
    // 反序集合输出
    Collections.reverse( list );
    System.out.println( list );
    // 求最大值
    System.out.println( Collections.max( list ) );   // 4
    //   使用指定的元素替换指定集合中的所有元素
    Collections.fill( list, 5 );
    System.out.println( list );

    十四、Arrays

    此类是java.util包下的一个工具类,不能实例化,主要包含一些操作数组或者返回数据的工具方法.此类的方法主要有如下功能

    • 排序

    • 二分搜索

    • 填充

    • 拷贝

    • 转换为流

    • 字符串显示数组

    • 转换为集合视图

    下面的代码是一些常见的操作

    // 将数组转换为集合视图
    ArrayList<Integer> list = new ArrayList<Integer>();
    Integer is[] = new  Integer[]{6,7,8};
    List<Integer> list2 =  Arrays.asList(is);
    list.addAll( list2 );
    System.out.println( list );

    // 将List转换为数组
    Object [] ins =  list.toArray();
    System.out.println( Arrays.toString( ins ) );

     

    十五、有序性与稳定性

    在阿里巴巴的编码规范中有这么一句话:合理利用集合的稳定性(order)和有序性(sort),避免集合的无序性和不稳定性带来的负面影响。稳定性指集合每次遍历的元素次序是一定的。有序性是指遍历的结果按某种比较规则依次排序的。

    如ArrayList是order/unsort,HashMap是unorder/unsort,TreeSet是order/sort

    比如下面的代码演示了HashMap的不稳定:

    Map<Integer,Integer> map = new HashMap<>();
    map.put(1,11);
    map.put(2,22);
    for(Map.Entry<Integer, Integer> entry:map.entrySet()) {
    System.out.println(entry.getKey());
    }
    System.out.println("------");
    map.put(17,17);
    for(Map.Entry<Integer, Integer> entry:map.entrySet()) {
    System.out.println(entry.getKey());
    }

    输出的结果是:由于新插入一个值导致两次遍历的结果是不一样的.这就是不稳定性

    1
    2
    ------
    1
    17
    2

     

    十六、null的处理

    集合类KeyValue父类说明
    Hashtable 不允许null 不允许null Dictionary 线程安全
    ConcurrentHashMap 不允许null 不允许null AbstractMap 锁分段
    TreeMap 不允许null 允许 AbstractMap 线程不安全
    HashMap 允许 允许 AbstractMap 线程不安全

    十七、异同点

    1.ArrayList和LinkedList

    (1)ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
    (2)对于随机访问get和set,ArrayList绝对优于LinkedList,因为LinkedList要移动指针。 
    (3)对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 
    这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

    2.HashTable与HashMap

    相同点:

    (1)都实现了Map、Cloneable、java.io.Serializable接口。
    (2)都是存储"键值对(key-value)"的散列表,而且都是采用拉链法实现的。

    不同点:

    (1)历史原因:HashTable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 。
    (2)同步性:HashTable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 。
    (3)对null值的处理:HashMap的key、value都可为null,HashTable的key、value都不可为null 。
    (4)基类不同:HashMap继承于AbstractMap,而Hashtable继承于Dictionary。

          Dictionary是一个抽象类,它直接继承于Object类,没有实现任何接口。Dictionary类是JDK 1.0的引入的。虽然Dictionary也支持“添加key-value键值对”、“获取value”、“获取大小”等基本操作,但它的API函数比Map少;而且Dictionary一般是通过Enumeration(枚举类)去遍历,Map则是通过Iterator(迭代M器)去遍历。 然而由于Hashtable也实现了Map接口,所以,它即支持Enumeration遍历,也支持Iterator遍历。
          AbstractMap是一个抽象类,它实现了Map接口的绝大部分API函数;为Map的具体实现类提供了极大的便利。它是JDK 1.2新增的类。
       
    (5)支持的遍历种类不同:HashMap只支持Iterator(迭代器)遍历。而Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历。

    3.HashMap、Hashtable、LinkedHashMap和TreeMap比较

         Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力。

         Hashtable 与 HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。

         LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。

         TreeMap实现SortMap接口,内部实现是红黑树。能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。 

    使用场景


         一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
         TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
         LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

    4.HashSet、LinkedHashSet、TreeSet比较

    Set接口
    Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
    Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不会接受这两个对象。

    HashSet
    HashSet有以下特点:
    ->  不能保证元素的排列顺序,顺序有可能发生变化。
    ->  不是同步的。
    ->  集合元素可以是null,但只能放入一个null。
        当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。
        注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

    LinkedHashSet
        LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
        LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

    TreeSet类
        TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
        TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0。

    5、Iterator和ListIterator区别

         我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器)。使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了。但是在使用的时候也是有不同的。List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:

    (1)ListIterator有add()方法,可以向List中添加对象,而Iterator不能
    (2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
    (3)ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
    (4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
    因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。

    6、Collection 和 Collections区别

    (1)java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。

    (2)java.util.Collections 是一个包装类(工具类/帮助类)。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,用于对集合中元素进行排序、搜索以及线程安全等各种操作,服务于Java的Collection框架。

  • 相关阅读:
    软件工程课程设计团队项目总结与项目报告
    个人总结
    团队项目UI
    黄金点
    wordcount
    小学运算
    第七周
    第八周
    第六周博客
    第五周博客
  • 原文地址:https://www.cnblogs.com/winton-nfs/p/14142178.html
Copyright © 2011-2022 走看看