集合框架(二)

Map
List、Set接口都是Collection的子接口,Map接口是与Collection完全独立的另外一个体系
List &Set vs Map
List &Set & Collection只能操作单个元素,Map可以操作一对元素,因为Map存储结构是key-value映射。

Map接口定义时使用了泛型 ,并且定义了两个泛型K和V,k表示key,规定键元素的数据类型,V表示value,规定值元素的数据类型
在这里插入图片描述
Map接口的实现类

  • HashMap:存储一组无序,key不能重复,value可以重复的元素,线程不安全,效率高;可以存储null的键和值.
  • LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历,原因:在原有的HashMap底层的结构基础上,添加了一对指针,分别指向前一个和后一个,对于频繁的遍历操作,此类的执行效率高于hashmap
  • Hashtable:存储一组无序,key不可以重复,value可以重复的元素,线程安全,不能存储null的key和value
  • TreeMap:存储一组有序,key不可以重复,value可以重复元素,可以按照key进行排序,底层使用的红黑树
    hashMap常规使用
public class Test6 {
    public static void main(String[] args) {

        HashMap hashMap = new HashMap();
        hashMap.put("h","Hello");
        hashMap.put("w","Hello");
        hashMap.put("j","Hello");
        hashMap.put("s","Hello");
        hashMap.put("m","Hello");
        hashMap.put("e","Hello");
        System.out.println(hashMap);
           hashMap.remove("e");
        System.out.println("删除之后"+hashMap);
            hashMap.put("m","Model");
        System.out.println("添加之后"+hashMap);
           if (hashMap.containsKey("a")){
               System.out.println("map中存在key=a");
           }else {
               System.out.println("集合中不存在key=a");
           }

           if (hashMap.containsValue("Java")){
               System.out.println("集合中存在value=Java");
           }else {
               System.out.println("集合中不存在value=Java");
           }

        Set keys = hashMap.keySet();
        System.out.println("集合中的key");
        Iterator iterator = keys.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        Collection values = hashMap.values();
        for (Object value : values) {
            System.out.println(value);
        }
        System.out.println("***********");

         iterator = keys.iterator();
          while (iterator.hasNext()){
              String key =(String) iterator.next();
              String value = (String) hashMap.get(key);
              System.out.println(key+"-"+value); 
          }
    }
}

hashMap用法与hashtable基本一样,他们的区别是,hashtable是线程安全的,但是性能较低,hashMap是非线程安全的,但是性能较高

HashMap,方法没有用synchronized修饰,所以是非线程安全的
在这里插入图片描述
Hashtable,方法用synchronized修饰,所以是线程安全的
在这里插入图片描述
Hashtable

public class Test7 {
    public static void main(String[] args) {

        Hashtable hashtable = new Hashtable();
        hashtable.put("h","Hello");
        hashtable.put("w","world");
        hashtable.put("j","Java");
        hashtable.put("s","JavaSE");

        hashtable.put("m","JavaME");
        hashtable.put("e","Javaee");
        System.out.println(hashtable);
            hashtable.remove("e");
        System.out.println(hashtable);
        System.out.println(hashtable.containsKey("a"));
        System.out.println(hashtable.containsValue("Java"));
        Set keys = hashtable.keySet();
        System.out.println(keys);
        Collection values = hashtable.values();
        System.out.println(values);
    }
}

HashMap和Hashtable,保存的元素都是无序的,Map的另外一个实现类Treemap主要功能是按照key对集合中元素进行排序

public class Test8 {
    public static void main(String[] args) {

        TreeMap treeMap = new TreeMap();
          treeMap.put(3,"Java");
        treeMap.put(5,"JavaME");
        treeMap.put(1,"HELLO");
        treeMap.put(6,"Javaee");
        treeMap.put(2,"world");
        treeMap.put(4,"JavaSE");
        Set keys = treeMap.keySet();
        Iterator iterator = keys.iterator();
        while (iterator.hasNext()){
            String key =(String) iterator.next();
            System.out.println(key+"--"+treeMap.get(key));
        }
    }
}

Map结构的理解
Map中的key:无序的,不可重复的,使用Set存储所有的key —>key所在的类要重写equals()和hashCode() (以hashmap为例)
Map中的value:无序的,可重复的,使用Collection存储所有的value
一个键值对:key-value构成了一个Entry对象。
Map中的entry:无序的,不可重复的,使用Set存储所有的entry

HashMap的底层实现原理?以jdk7为例说明:
HashMap map = new HashMap();
在实例化以后,底层创建了一个长度是16的一维数组Entry[ ] table
…假设此时的场景是该map集合已经执行过了多次put…
map.put(key1,value1):
首先,调用key1所在的类的hashCode()计算key1的哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
如果此位置上的数据为空,此时的key1-value1添加成功。情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表的形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。情况2
如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在的类的equals(key2):

  • 如果equals()返回false:此时key1-value1添加成功 情况3
  • 如果equals返回true:使用value1替换value2
    补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。在不断添加数据的过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,才回去扩容,默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来,一旦扩容,元素对象的哈希值需要重新计算

JDK8相较于jdk7在底层实现方面的不同:

  • new HashMap():底层没有创建一个长度为16的数组
  • jdk8底层数组是Node[ ],而非Entry[ ]
  • 首次调用put方法时,底层创建长度为16的数组
  • jdk7底层结构只有:数组+链表,jdk8中底层结构:数组+链表+红黑树,当数组的某一个索引位置上的元素以链表形式存在的数据个数>8 且当前数组的长度 > 64时,此时此索引位置上的所有数据改为红黑树存储

几个重要参数:

  • DEFAULT_INITIAL_CAPACITY:hashmap的默认容量,16
  • DEFAULT_LOAD_FACTOR:hashmap的默认加载因子:0.75
  • threshold:扩容的临界值,=容量填充因子:160.75=>12
  • TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
    为什么hashmap要提前扩容而不是满了再扩容以及为什么它的的加载因子是0.75?
    hashmap它底层的数组不一定会满,因为他可能会出现链表的情况,如果等到它满了再去扩容,就可能会导致出现链表的情况表较多,它是为了尽可能让hashmap中出现链表的情况变少,因为遍历的时候会影响效率,因此才会提前扩容,想要出现链表的情况尽可能少,那摩就得加载因子越小越好,但是如果加载因子太小了,那摩就会造成数组经常扩容,导致数组的利用率变低了,但是如果加载因子太大了,又会导致出现链表的情况变多,因此如果想要做到两者兼顾的情况,那就得有一个合适的加载因子,通过大量统计学测试,得出让加载因子为0.75比较好,是两种情况趋于平衡

LinkedHashMap的底层实现原理
在这里插入图片描述
记录了添加元素的顺序,因此是有序的集合

Collections工具类
Collection接口,List和Set的父接口。
Collections 不是接口,它是一个工具类,专门提供了一些对集合的操作,方便开发者去使用,完成相应的业务功能。

Collections针对集合工具类,Collection
Arrays针对数组的工具类,Array
在这里插入图片描述
在这里插入图片描述

/**
 *   java.util.Collection是集合工具类,用来对集合进行操作,部分方法如下:
 *       - public static <T> boolean addAll(Collection<T> C,T... elements)往集合中添加一些元素
 *       - public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序
 */
public class Demo01Collections {
    public static void main(String[] args) {

          ArrayList<String> list = new ArrayList<>();
//              //往集合中添加多个元素
//            list.add("a");
//            list.add("b");
//          list.add("c");
//           list.add("d");

        //     public static <T> boolean addAll(Collection<T> c,T... elements): 往集合中添加一些元素。
        Collections.addAll(list,"a","b","c","d");
        System.out.println(list);
           // public static void shuffle(List<?> list);  打乱集合顺序
         Collections.shuffle(list);
        System.out.println(list);
    }
}
public class Person implements Comparable<Person> {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

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

    @Override
    public int compareTo(Person o) {
      //  return 0;   //认为元素都是相同的

       // return this.age - o.age;   //按照年龄升序排列

          return o.age - this.age;  //按照年龄降序排列
    }
}
/**
 *  java.utils.Collections是集合工具类,用来对集合进行操作,部分方法如下:
 *       public static <T> void sort(list<T> list):将集合中的元素按照默认规则排序
 *
 *
 *      注意:
 *        sort(List<T> list) 使用原理
 *         被排序的集合里边存储的元素,必须实现Comparable接口,重写接口中的方法compareTo定义的排序规则
 *
 *       Comparable接口的排序规则:
 *          自己(this)- 参数  : 升序
 *
 *
 */
public class Demo02Sort {

    public static void main(String[] args) {

        ArrayList<Integer> list = new ArrayList<>();
           list.add(1);
           list.add(3);
           list.add(2);
        System.out.println(list); // [1,3,2]

            //public static <T> void sort(list<T> list):将集合中的元素按照默认的规则进行排序
        Collections.sort(list);   //默认的是升序
        System.out.println(list);



             ArrayList<Person> list1 = new ArrayList<>();
                 list1.add(new Person("张三",18));
                 list1.add(new Person("李四",20));
                 list1.add(new Person("王五",15));
        System.out.println(list1);
            Collections.sort(list1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值