zoukankan      html  css  js  c++  java
  • 集合-下

    Set接口

    set接口表示一个无序,唯一的容器。

    set接口提供的方法(方法其实和list接口的方法超级像,也是增,删,查)

    public static void main(String[] args) {
            /**
             * 增:add/addAll
             * 删:clear/remove/removeAll/retainAll
             * 改:
             * 查:contains/containsAll
             * 遍历:iterator
             * 其他:size/isEmpty
             */
             Set<Integer> set=new HashSet<Integer>();
             //[1]添加
             set.add(2);
             set.add(3);
             set.add(1);
             System.out.println(set);
             //[2]删除
             set.remove(2);
             set.clear();//清空
             //[3]查看是否包含
             System.out.println(set.contains(3));
             //其它
             System.out.println(set.size());
             System.out.println(set.isEmpty());
        }

    set遍历

    public static void main(String[] args) {
            //遍历
            Set<String> set=new HashSet<String>();
            set.add("apple");
            set.add("banana");
            set.add("coco");
            System.out.println(set);
            //快速遍历
            for(String item:set){
                System.out.println(item);
            }
            //迭代器
            Iterator<String> it=set.iterator();
                while (it.hasNext()) {
                    String item = it.next();
                    System.out.println(item);                
                }    
        }

    set的三个实现类:HashSet、LinkedHashSet、TreeSet。

    一,HashSet

      hashset底层数据是hash表,hashset的线程也不安全。

    hash表工作原理:

    *理解:每个元素都有一个唯一的哈希码,然后利用函数公式可以把无数个哈希码放置在有限的储存位置上,数字的哈希码就是数字本身,那么自定义的对象又怎么存储到hashset中呢?

    解决方法很简单:只需要在自定义对象的元素实现hashCode方法和equals方法即可

    public class Student {
        private String name;
        private String type;
        private int age;
    
        //设置器访问器和有参无参构造省略
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + age;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            result = prime * result + ((type == null) ? 0 : type.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Student other = (Student) obj;
            if (age != other.age)
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            if (type == null) {
                if (other.type != null)
                    return false;
            } else if (!type.equals(other.type))
                return false;
            return true;
        }
    
        @Override
        public String toString() {
            return "Student [name=" + name + ", type=" + type + ", age=" + age
                    + "]";
        }
    }

    测试类

    public static void main(String[] args) {
            Student st1=new Student("wnagyi","001",19);
            Student st2=new Student("zhangsan","001",20);
            Student st3=new Student("lisi","001",22);
            HashSet<Student> set=new HashSet<Student>();  //自定义对象存储
            set.add(st2);
            set.add(st3);
            set.add(st1);
            System.out.println(set);
            //快速遍历
            for (Student item:set) {
                System.out.println(item);
            }
            //迭代器
            Iterator<Student> it=set.iterator();
            while (it.hasNext()) {
                Student item = it.next();
                System.out.println(item);
            }
        }

    其实 hashset的增删查效率都还可以,但就是没法有序。

    那set接口的第二个实现类就出来了

    二,linkedhashset

    底层数据结构哈希表+链表

    哈希表用于散列元素;链表用于维持添加顺序。

    如果要添加自定义对象元素,也需要重写hashCode和equals方法。

    理解:这里所谓的有序也只是单指在输入元素的时候的输入顺序,而且其他的增删改查方法都和hashset一样的。

    三,treeset

    底层数据结构是二叉树。

    TreeSet 存储的数据按照一定的规则存储。存储规则让数据表现出自然顺序。

    treeset工作原理:

    添加一个新元素t的存储的步骤

    [1] 如果集合无元素,t直接加入;如果集合有元素,t和根节点比较;

    [2] 如果t小于根节点;把t放到根节点的左子树上;重复1-3步骤

    [3] t大于根节点;把t放到根节点的右子树上;重复1-3步骤

     理解:添加的新元素从根节点开始比较,比根节点小的往左边走,大的往右边走,相同的被去掉。

    输出时按照一定的规则:左子树->根节点->右子树

     如果是数字类型的话放入元素还比较好比较,如果放入的是自定义的元素(无法正常通过大小去比较),那么很有可能会出现ClassCastException(类转换异常)

    ,所以我们得提供比较策略(内部比较器和外部比较器)

    1,内部比较策略

    当一个自定义对象实现Comparable并实现compareTo方法时,通过指定具体的比较策略,此时称为内部比较器

    public class Student implements Comparable<Student> {
        private String name;
        private String type;
        private int age;
    
        //设置器访问器和有参无参构造省略
        //hashcode和equals方法重写也省略了
    
        @Override
        public int compareTo(Student o) {
            if(this.getAge()<o.getAge()) {
                return -1;
            }else if(this.getAge() == o.getAge()) {  //多种比较情况:如果这里相等了,treeset会认为两个元素相同而删除一个的,所以还得在这里继续比较其它的不同的属性
                return 0;
            }else {
                return 1;
            }
        }
    }

    2,外部比较策略

    当实际开发过程中不知道添加元素的源代码、无权修改别人的代码,此时可以使用外部比较器。

    Comparator 位于java.util包中,定义了compare(o1,o2) 用于提供外部比较策略。

    TreeSet接受一个指定比较策略的构造方法,这些比较策略的实现类必须实现Comparator

    接口。

    需求:按照字符串的长度比较

    public static void main(String[] args) {
            TreeSet<String> set=new TreeSet<String>(new Comparator<String>() {
    
                @Override
                public int compare(String o1, String o2) {
                    return o1.length()-o2.length();
                }
            }); //标记的地方都是匿名内部类 里面重写一个比较方法。
            set.add("banana");
            set.add("coco");
            set.add("apple");
            set.add("apple");
            System.out.println(set);
    
        }

    接下来介绍与List接口和Set接口齐名的Map接口

    Map接口称为键值对集合或者映射集合,其中的元素(entry)是以键值对(key-value)的形式存在。

    Map接口中都是通过key来操作键值对,一般key是已知。通过key获取value

    举一反三:

    Map 容器接口中提供了增、删、改、查的方式对集合进行操作;

    提供了遍历方法;

    以及三个实现类(HashMap,LinkedHashMap,TreeMap)

    那下面一个个来介绍一下:

    /**      增删改查等方法就不用多写了,和前面不一样的是个别代码的变化
             * 增:put/putAll
             * 删:clear/remove
             * 改:put
             * 查:get/containsKey/containsValue
             * 其他:isEmpty/size
             */

    遍历:

    public static void main(String[] args) {
             Map<String, String> map=new HashMap<String,String>();
             map.put("A", "apple");
             map.put("B", "banana");
             map.put("C", "coco");
             System.out.println(map);
             //快速遍历
             Set<String> key=map.keySet();
             for(String item:key){
                 System.out.println(item+"=>"+map.get(item));
             }
    //迭代器 Iterator
    <String> it=key.iterator(); while (it.hasNext()) { String item = it.next(); System.out.println(item+"=>"+map.get(item)); } }

    三个实现类之

    1,HashMap

    key以HashSet存储

    public static void main(String[] args) {
            
            /*  以string对象向hashmap中添加元素(默认是可以自然排序的,不需要重写方法)
            HashMap<String, Object> map = new HashMap<String,Object>();
            
            ArrayList<String> list1 = new ArrayList<String>();
            list1.add("alex");
            list1.add("alice");
            list1.add("allen");
            map.put("A", list1);
            
            
            ArrayList<String> list2 = new ArrayList<String>();
            list2.add("ben");
            list2.add("bill");
            map.put("B", list2);
            
            System.out.println(map);
            */
            //以自定义对象向hashmap中添加元素(必须要重写student类的hashcode和equals方法)
            HashMap<Student, Object> map = new HashMap<Student,Object>();
            
            ArrayList<String> list1 = new ArrayList<String>();
            list1.add("alex");
            list1.add("alice");
            list1.add("allen");
            Student s1 = new Student("001", "大狗", 20);
            map.put(s1, list1);
            
            
            ArrayList<String> list2 = new ArrayList<String>();
            list2.add("ben");
            list2.add("bill");
            Student s2 = new Student("001", "大狗", 20);
            // 修改
            map.put(s2, list2);
            System.out.println(map);
            
        }

    2,LinkedHashMap

    key以LinkedHashSet存储。

    哈希表散列key,链表维持key的添加顺序。

    这个不同于hashmap的地方就是:添加元素的顺序也可以是一种顺序

    3,TreeMap

    key以TreeSet存储

    特点也是需要提供比较策略。

    TreeMap<String, Object> map = new TreeMap<String,Object>(new Comparator<String>() {
    
                @Override
                public int compare(String o1, String o2) {
                    return o1.length() - o2.length();
                }
            });  //匿名内部类+比较策略
            
            ArrayList<String> list2 = new ArrayList<String>();
            list2.add("ben");
            list2.add("bill");
            map.put("Aa", list2);
            
            ArrayList<String> list1 = new ArrayList<String>();
            list1.add("alex");
            list1.add("alice");
            list1.add("allen");
            map.put("B", list1);
            
            System.out.println(map);
  • 相关阅读:
    November 13th 2016 Week 47th Sunday The 1st Day
    November 12th 2016 Week 46th Saturday
    November 11th 2016 Week 46th Friday
    November 10th 2016 Week 46th Thursday
    November 9th 2016 Week 46th Wednesday
    November 8th 2016 Week 46th Tuesday
    windows 7文件共享方法
    Win7无线网络共享设置方法
    常量指针和指针常量
    如何查找局域网的外网ip
  • 原文地址:https://www.cnblogs.com/zhangxiong-tianxiadiyi/p/10816402.html
Copyright © 2011-2022 走看看