ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JavaSet接口实现类(hashSet、LinkedHashSet、TreeSet),附两道常见面试题

2020-11-25 18:00:00  阅读:225  来源: 互联网

标签:面试题 LinkedHashSet name hashSet age add new Test01 public


Collection子接口二:Set

  • Set接口是Collection的子接口,Set接口没有提供额外的方法,直接调用Collection的方法就可以

  • Set集合中不允许添加相同的元素

  • Set判读两个对象是否相同不是使用==运算符,而是根据equals方法

  • Set:元素无序、不可重复的集合

    • hashSet:Set接口的主要实现类:线程不安全,可以存储null值
      • LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历
    • TreeSet:可以按照添加对象的指定属性,进行排序
  • Set无序性:不等于随机性,存储的数据在底层数组中并非按照数组索引的顺序添加,而是按照数据的哈希值决定的

  • Set不可重复性:保证添加的元素在按照equals()判断时,不能返回true,即:相同的元素只能添加一个

  • 添加元素的过程:以HashSet为例

    • 1.在向HashSet中添加元素a,首先调用a所在类的hashCode()方法,计算元素a的哈希值
    • 2.此哈希值接着通过某种算法计算出在HashSet底层数组中的存储位置(即为索引位置),以此判断数组此位置上是否已经有元素
      • 2.1.如果此位置上没有其他元素,则直接将元素a添加到此位置上
      • 2.2.如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较a与b的hash值
        • 2.2.1.如果哈希值不相同,则将元素a添加到b的下面(同一个位置,以链表的方式存储)
        • 2.2.2.如果哈希值相同,进一步调用b所在类的equals()方法
          • 2.2.2.1.equals()返回true,则两个元素相同,添加失败
          • 2.2.2.2.equals()返回false,则将元素a添加到b的下面(同一个位置,以链表的方式存储)
  • HashSet底层也是数组(数组+链表的结构),初始容量为16,如果使用率超过0.75(12),就会扩大容量为原来的2倍(32,64,128…)

  • 对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等等规则,即:相等的对象必须具有相等的散列码

  • 对象中用作equals()方法比较的field,都应该用来计算hashCode

package www.bh.c.settest;

public class Test01 {
    private String name;
    private int age;

    public Test01() {
    }

    public Test01(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
   //重写equals()
    @Override
    public boolean equals(Object o) {
        System.out.println("=================");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Test01 test01 = (Test01) o;

        if (age != test01.age) return false;
        return name != null ? name.equals(test01.name) : test01.name == null;
    }
   //重写hashCode()
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}
  • 注:为什么以上重写hashCode()会出现31数字?

    • 选择系数的时候如果选择大的,查找的效率会更高
    • 31只占用了5bits,相乘造成数据溢出的概率较小
    • 31可以由i*31==(i<<5)-1来表示,提高了算法效率
    • 31位一个素数(底下不能再分解),也减少了冲突
  • LinkedHashSet

    • LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,以此来记录此数据的前一个数据和后一个数据
    • 对于频繁的遍历操作,LinkedHashSet效率要高于HashSet
package www.bh.c.settest;
import java.util.Iterator;
import java.util.LinkedHashSet;

public class Test02 {
    public static void main(String[] args) {
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        linkedHashSet.add(123);
        linkedHashSet.add(45);
        linkedHashSet.add(0);
        linkedHashSet.add("AA");
        linkedHashSet.add("dd");
        linkedHashSet.add("DD");
        linkedHashSet.add("BB");
        //遍历,每个数据还维护了两个引用,以此来记录此数据的前一个数据和后一个数据,并不是有序的
        Iterator iterator=linkedHashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());/*123
45
0
AA
dd
DD
BB*/                                          
        }
    }
}
  • TreeSet

    • 向TreeSet中添加数据,要求是相同类的对象

    • TreeSet采用的是红黑树的存储结构,元素有序,查询速度比List快

    • 两种排序方式:自然排序(实现Comparable接口),定制排序(Comparator)

      package www.bh.c.settest;
      import java.util.Iterator;
      import java.util.TreeSet;
      
      public class Test03 {
          public static void main(String[] args) {
              TreeSet treeSet = new TreeSet();
              treeSet.add(new Test01("张三",12));
              treeSet.add(new Test01("李四",32));
              treeSet.add(new Test01("小明",15));
              treeSet.add(new Test01("李四",13));
              treeSet.add(new Test01("华子",7));
              Iterator iterator = treeSet.iterator();
              while (iterator.hasNext()){
                  System.out.println(iterator.next());//报错:ClassCastException
              }
          }
      }
      
      • 自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals()
      //1.创建对象类,并重写Comparable接口的CompareTo方法
      package www.bh.c.settest;
      
      public class Test01 implements Comparable {
      private String name;
          private int age;
      
          public Test01() {
          }
      
          public Test01(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @Override
          public boolean equals(Object o) {
              System.out.println("=================");
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
      
              Test01 test01 = (Test01) o;
      
              if (age != test01.age) return false;
              return name != null ? name.equals(test01.name) : test01.name == null;
          }
      
          @Override
          public int hashCode() {
              int result = name != null ? name.hashCode() : 0;
              result = 31 * result + age;
              return result;
          }
      
          //重写Comparable接口的CompareTo方法,按照姓名从小到大排序
          @Override
          public int compareTo(Object o) {
              if (o instanceof Test01){
                  Test01 test01=(Test01)o;
                  return this.name.compareTo(test01.name);
              }else {
                  throw new RuntimeException("类型不匹配");
              }
          }
      
          @Override
          public String toString() {
              return "Test01{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
      
      //2.将treeSet中的元素按照写好的compareTo()遍历
      package www.bh.c.settest;
      import java.util.Iterator;
      import java.util.TreeSet;
      
      public class Test03 {
          public static void main(String[] args) {
              TreeSet treeSet = new TreeSet();
              treeSet.add(new Test01("张三",12));
              treeSet.add(new Test01("李四",32));
              treeSet.add(new Test01("小明",15));
              treeSet.add(new Test01("李四",13));
              treeSet.add(new Test01("华子",7));
              Iterator iterator = treeSet.iterator();
              while (iterator.hasNext()){
                  System.out.println(iterator.next());
                  /*
                  Test01{name='华子', age=7}
                  Test01{name='小明', age=15}
                  Test01{name='张三', age=12}
                  Test01{name='李四', age=32}
                  */
                  //TreeSet中存的元素为不重复的,如果名字重复则存储失败,所以按方法遍历不到
              }
          }
      }
      
      //3.优化compareTo()方法
      //按照姓名从大到小排序,年龄从小到大排序
          @Override
          public int compareTo(Object o) {
              if(o instanceof Test01){
                  Test01 test01=(Test01) o;
                  int i = -this.name.compareTo(test01.name);
                  if (i!=0){
                      return i;
                  }else {
                      return Integer.compare(this.age,test01.age);
                  }
              }else {
                  throw new RuntimeException("类型不匹配");
              }
          }
      
      package www.bh.c.settest;
      import java.util.Iterator;
      import java.util.TreeSet;
      
      public class Test03 {
          public static void main(String[] args) {
              TreeSet treeSet = new TreeSet();
              treeSet.add(new Test01("张三",12));
              treeSet.add(new Test01("李四",32));
              treeSet.add(new Test01("小明",15));
              treeSet.add(new Test01("李四",13));
              treeSet.add(new Test01("华子",7));
              Iterator iterator = treeSet.iterator();
              while (iterator.hasNext()){
                  System.out.println(iterator.next());
                  /*
                  Test01{name='李四', age=13}
                  Test01{name='李四', age=32}
                  Test01{name='张三', age=12}
                  Test01{name='小明', age=15}
                  Test01{name='华子', age=7} 
                  */
              }
          }
      }
      
      • 定制排序中:比较两个对象是否相同的标准为:compare()返回0,不再是equals()
      package www.bh.c.settest;
      import java.util.Comparator;
      import java.util.Iterator;
      import java.util.TreeSet;
      
      public class Test04 {
          public static void main(String[] args) {
              Comparator comparator=new Comparator(){
                  //年龄从小到大排列
                  @Override
                  public int compare(Object o1, Object o2) {
                      if (o1 instanceof Test01&&o2 instanceof Test01){
                          Test01 test01=(Test01)o1;
                          Test01 test02=(Test01)o2;
                          return Integer.compare(test01.getAge(),test02.getAge());
                      }else {
                          throw new RuntimeException("输入类型有误");
                      }
                  }
              };
              TreeSet treeSet = new TreeSet(comparator);
      
              treeSet.add(new Test01("张三",12));
              treeSet.add(new Test01("李四",32));
              treeSet.add(new Test01("小明",15));
              treeSet.add(new Test01("李四",13));
              treeSet.add(new Test01("华子",7));
              Iterator iterator = treeSet.iterator();
              while (iterator.hasNext()){
                  System.out.println(iterator.next());
              }
          }
      }
      
      
  • 面试题:

  • 1.在List内去除重复数字值,要求尽量简单

package www.bh.c.settest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class Test05 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Integer(1));
        list.add(new Integer(2));
        list.add(new Integer(2));
        list.add(new Integer(3));
        List list1 = duplicateList(list);
        Iterator iterator=list1.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());//[1,2,3]
        }
    }
    //将list先放到HashSet中,再返回一个新的List
    public static List duplicateList(List list){
        HashSet hashSet = new HashSet();
        hashSet.addAll(list);
        return new ArrayList(hashSet);
    }
}

2.以下代码输出的结果是什么?

package www.bh.c.settest;
import java.util.HashSet;

public class Test06 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        Test01 p1=new Test01("A",10);
        Test01 p2=new Test01("B",10);
        hashSet.add(p1);
        hashSet.add(p2);
        System.out.println(hashSet);//
        p1.name="C";
        hashSet.remove(p1);
        System.out.println(hashSet);//
        hashSet.add(new Test01("C",10));
        System.out.println(hashSet);//
        hashSet.add(new Test01("A",10));
        System.out.println(hashSet);//
    }
}
/*
答案:
[Test01{name='B', age=10}, Test01{name='A', age=10}],
[Test01{name='B', age=10}, Test01{name='C', age=10}],
[Test01{name='C', age=10}, Test01{name='B', age=10}, Test01{name='C', age=10}],
[Test01{name='C', age=10}, Test01{name='B', age=10}, Test01{name='C', age=10}, Test01{name='A', age=10}]
*/
//注:主要要先考虑哈希值

标签:面试题,LinkedHashSet,name,hashSet,age,add,new,Test01,public
来源: https://blog.csdn.net/insist_to_learn/article/details/110138314

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有