java基础 之 集合与栈的使用(二)

发布于:2024-08-01 ⋅ 阅读:(176) ⋅ 点赞:(0)

上文介绍了List接口的实现类,本文来介绍Set和Map
点击这里跳转到上一篇,java基础 之 集合与栈的使用(一)

在这里插入图片描述

List 和 Set的比较
List Set
有序性 保证按插入顺序排序 存储和取出顺序不一致
唯一性 可以重复 元素唯一
获取元素 可以根据索引值操作或者获取元素 不能根据索引值操作
Set接口
对于set的无序该怎么理解?
  • 无序是指读取数据的顺序不一定和插入数据的顺序一样
(一)实现类:HashSet
  • 特点

    • HashSet底层使用的是HashMap
    • 不保证元素的顺序,
    • 数据不能有重复的
    • 元素值允许有NULL
    • 线程不安全
  • HashSet集合的一些方法

import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;

public class TestHashSet {
    public static void main(String[] args) {
        HashSet set = new HashSet<>();
        Random random = new Random();
        for(int i=0;i<20;i++){
            // add(Object o):向Set集合中添加元素,不允许添加重复数据。
            System.out.print(set.add(random.nextInt(15))+" ");
        }
        // size():返回Set集合中的元素个数
        System.out.println(set.size());
        //.contains(Object o):判断集合中是否包含obj元素。
        System.out.println(set.contains(23));
        //.remove(Object o): 删除Set集合中的obj对象,删除成功返回true,否则返回false。
        System.out.println(set.remove(23));
        //.isEmpty():如果Set不包含元素,则返回 true。
        System.out.println(set.isEmpty());

        // 打印set中内容,方法一:迭代法
        Iterator<Integer> iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next()+"-- ");
        }
        // 打印set中内容看,方法二:foreach
        for (Object o : set) {
            System.out.print(o+" ");
        }
        // .clear(): 移除此Set中的所有元素。返回类型为void
        set.clear();

    }
}
(二)实现类:LinkedHashSet
  • LinkedHashSet 特点

    • 继承了HashSet,是在HashSet的基础上维护了元素添加顺序的功能
    • LinkedHashSet是List接口的一个实现类
    • 底层使用的是HashSet,同时使用链表维护元素的插入顺序
    • 元素有序且唯一,因为链表保证了元素有序,哈希表保证元素唯一
    • LinkedHashSet线程不安全
  • LinkedList集合的一些方法

    LinkedHashSet继承于HashSet,它的源码很少,只有几个构造函数,基本上都是调用父类HashSet的构造函数。
    方法同HashSet,这里就不写了。

【代码部分】HashSet 和 LinkedHashSet
	import java.util.HashSet;
	import java.util.Iterator;
	import java.util.LinkedHashSet;
	import java.util.Random;
	
	public class TestLinkedHashSet {
	    public static void main(String[] args) {
	        HashSet hashSet = new HashSet();
	        LinkedHashSet linkedHashSet = new LinkedHashSet();
	
	        Random random = new Random(1);
	        System.out.println("添加的数字内容:");
	        for(int i=0;i<20;i++){
	            int element = random.nextInt(15);
	            System.out.print(element+" ");
	            hashSet.add(element);
	            linkedHashSet.add(element);
	        }
	        System.out.println();
	
	        Iterator hash = hashSet.iterator();
	        System.out.println("set集合打印:");
	        while(hash.hasNext()){
	            System.out.print(hash.next()+" ");
	        }
	        System.out.println();
	        System.out.println("linkedSet集合打印:");
	        Iterator linked = linkedHashSet.iterator();
	        while (linked.hasNext()){
	            System.out.print(linked.next()+" ");
	        }
	        System.out.println();
	        System.out.println("---------------------------------");
	        HashSet<String> setString = new HashSet();
	        LinkedHashSet<String> linkedString= new LinkedHashSet();
	
	        System.out.println("添加的字母内容:");
	        for(int i=0;i<20;i++){
	            char letter = (char) ('a'+random.nextInt(26));
	            System.out.print(letter+" ");
	            setString.add(String.valueOf(letter));
	            linkedString.add(String.valueOf(letter));
	        }
	        Iterator s_setString = setString.iterator();
	        System.out.println();
	        System.out.println("set集合打印:");
	        while(s_setString.hasNext()){
	            System.out.print(s_setString.next()+" ");
	        }
	        System.out.println();
	        System.out.println("linkedSet集合打印:");
	        Iterator linked_setString = linkedString.iterator();
	        while (linked_setString.hasNext()){
	            System.out.print(linked_setString.next()+" ");
	        }
	    }
	}

在这里插入图片描述

代码的运行结果是否跟自己想象中的一样?
不一样的话,知道是怎么回事不?

浅谈HashSet 和 LinkedHashSet的打印结果
  • 疑问一:set的无序是怎么回事?

    集合所说的序,是指元素存入集合的顺序,当元素存储顺序和取出顺序一致时就是有序,否则就是无序。

  • 疑问二:为什么HashSet打印的值是有序的?

    HashSet真实的情况是有序的,只不过它是通过内部HashCode方法计算hash值后自动进行了排序,所以读取的是经过内部排序后的数据,且此数据每次结果都是一样的顺序。

  • 疑问三:HashSet打印的值一直是有序的吗?

    如果添加的是Integer类型的,打印出来一直是有序的,因为Integer类型hashCode()的返回值就是其int值本身
    如果添加的不是Integer类型的,当数组长度小于16时,打印出来是无序的,大于等于16就是有序的,与扩容机制有关。
    (点击这里了解为啥16是分界线)Java遍历HashSet为什么输出是有序的?

(三)实现类: TreeSet
  • 特点

    • TreeSet内部使用的是TreeMap,TreeMap是基于红黑树实现的
    • 插入数据内部有两种排序方法:自然排序 和 定制排序
    • TreeSet会对插入的数据排序,所以输入和输出顺序不一致
    • 值唯一,但是不可以为null
    • 线程不安全
  • TreeSet集合的使用

    • 输出时排序是按照字典序排序的方式

      public class TestTreeSet {
          public static void main(String[] args) {
              TreeSet ts=new TreeSet();
              ts.add("hello");
              ts.add("world");
              ts.add("abc");
              Iterator it=ts.iterator();
      
              // 输出 : 按照字典序排序的方式进行排序
              while(it.hasNext()) {
                  System.out.print(it.next());    // 输出结果:abd hello world
              }
          }
      }
      

      ‌字典序排序是一种按照字母表的顺序对字符串进行排序的方法。 其基本原理是在比较两个字符串时,从左到右逐个字符进行比较。如果某个位置的字符不同,则较小的字符排在前面;如果所有字符都相同,则较短的字符串排在前面。‌

    • 如果插入的是自定义对象 需要让类实现 Comparable 接口并且必须要重写compareTo

      /***创建一个Person类
      */
      public class Person implements Comparable{
          String name;
          int age;
          Person(String name,int age)
          {
              this.name=name;
              this.age=age;
          }
          @Override
          public int compareTo(Object o) {
              Person p=(Person)o;
              //先对姓名字典序比较 如果相同 比较年龄
              if(this.name.compareTo(p.name)!=0) {
                  return this.name.compareTo(p.name);
              }
              else
              {
                  if(this.age>p.age) return 1;
                  else if(this.age<p.age) return -1;
              }
              return 0;
          }
      }
      
      import java.util.Iterator;
      import java.util.TreeSet;
      
      public class TestTreeSet {
          public static void main(String[] args) {
              TreeSet treeSet=new TreeSet();
              treeSet.add(new Person("hello",21));
              treeSet.add(new Person("world",12));
              treeSet.add(new Person("abc",8));
              treeSet.add(new Person("Abc",12));
              Iterator it=treeSet.iterator();
              while(it.hasNext())
              {
                  Person p=(Person)it.next();
                  System.out.println(p.name+":"+p.age);
              }
          }
      }
      ----------------运行结果-----------------
      Abc:12
      abc:8
      hello:21
      world:12
      
总结

1、HashSet:HashSet的性能基本上比LinkedHashSet和TreeSet要好,特别是添加和查询,这也是用的最多的两个操作
2、LinkedHashSet的查询稍慢一些,但是他可以维持元素的添加顺序。所以只有要求当插入顺序和取出顺序一致的时候 才使用LinkedHashSet。
3、TreeSet只有在需要对元素进行排序时使用