Java中的集合框架

Copyright©stonee

写在前面,本篇文章将对 集合框架自顶向下有一个大概 的描述,介绍常用集合的API函数以及某些重要API函数的实现过程。 适合新人上手 。具体集合的源码分析将会在以后的专栏中推出。

1. 集合的诞生原因以及特点

Java的最初版本只为最长用的数据结构提供了很少的一组类:Vector, Stack, Hashtable, BitSet, Enumeration 。显然这些接口离全面的集合类库相差甚远。从JavaSE1.2开始,集合框架诞生。

  • 私以为,集合和数组相比:
  1. 数组的长度是固定的,当添加的元素超过了数组的长度的时候,需要重新定义比较麻烦;Java内部给我们提供了集合类,可以储存任意长度的任意对象,长度随着元素的增加而增加,减少而减少。即数组长度固定,集合长度动态变化;
  2. 对于数组来说存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值;集合只能存储引用数据类型。当然也可以存储基本数据类型,不过存储的时候会自动装箱。
  • 同时, 集合类给我们提供了高效操纵数据的各种可能。我们不必再纠结于快排、堆排序等排序方式,也不用担心不会写红黑树,B+树等数据结构,集合框架完全可以为我们完成这些工作(PS:这些东西还是要学习的,对个人的提升帮助很大!)
  • Java中集合的接口和实现是分离的,每一个实现都可以通过一个实现了接口的类表示

2. Java集合框架图表

在这里插入图片描述

3. 上述图片pdf版以及文本形式下载地址:

我真的尽力了,但是由于图上的内容太多,所以我把pdf格式放到了这里,点击转到
当然,如果没有c币的话,可以通过在下面留言或者到我的博客中找到我的联系方式^ _ ^

4. 具体集合中的API和基础原理

附上Java11的API网址

  • 基本的集合方法

    • Collection :对于单值的操作

      boolean	add​(E e)	//Ensures that this collection contains the specified element (optional operation).
      boolean	addAll​(Collection<? extends E> c)	//Adds all of the elements in the specified collection to this collection (optional operation).
      void	clear()	//Removes all of the elements from this collection (optional operation).
      boolean	contains​(Object o)	//Returns true if this collection contains the specified element.
      boolean	containsAll​(Collection<?> c)	//Returns true if this collection contains all of the elements in the specified collection.
      boolean	isEmpty()	//Returns true if this collection contains no elements.
      abstract Iterator<E>	iterator()	//Returns an iterator over the elements contained in this collection.
      boolean	remove​(Object o)	//Removes a single instance of the specified element from this collection, if it is present (optional operation).
      boolean	removeAll​(Collection<?> c)	//Removes all of this collection's elements that are also contained in the specified collection (optional operation).
      boolean	retainAll​(Collection<?> c)	//Retains only the elements in this collection that are contained in the specified collection (optional operation).
      Object[]	toArray()	//Returns an array containing all of the elements in this collection.
      <T> T[]	toArray​(T[] a)	//Returns an array containing all of the elements in this collection; the runtime type of the returned array is that of the specified array.
      String	toString()	//Returns a string representation of this collection.
      

      这里的每个方法都要手动敲一遍

      注意:其中后缀有All的方法传的参数必须是集合!

      还有List中的remove()方法,如果要删除的是整型的话,只能通过索引,此时元素不会像其他类型一样自动装箱,否则会弄混

    • Map:对于两个映射之间的操作

      void	clear()	//Removes all of the mappings from this map (optional operation).
      protected Object	clone()	//Returns a shallow copy of this AbstractMap instance: the keys and values themselves are not cloned.
      boolean	containsKey​(Object key)	//Returns true if this map contains a mapping for the specified key.
      boolean	containsValue​(Object value)	//Returns true if this map maps one or more keys to the specified value.
      boolean	equals​(Object o)	//Compares the specified object with this map for equality.
      V	get​(Object key)	//Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
      int	hashCode()	//Returns the hash code value for this map.
      boolean	isEmpty()	//Returns true if this map contains no key-value mappings.
      Set<K>	keySet()	//Returns a Set view of the keys contained in this map.
      V	put​(K key, V value)	//Associates the specified value with the specified key in this map (optional operation).
      void	putAll​(Map<? extends K,? extends V> m)	//Copies all of the mappings from the specified map to this map (optional operation).
      V	remove​(Object key)	//Removes the mapping for a key from this map if it is present (optional operation).
      int	size()	//Returns the number of key-value mappings in this map.
      String	toString()	//Returns a string representation of this map.
      Collection<V>	values()	//Returns a Collection view of the values contained in this map.
      

      同上,这些也必须要敲一遍

  • AbstractCollection重写了Object类的toString方法,这使得它的派生类都可打印出字符串

  • contains()底层用equals实现

  • linkedlist中会有额外的方法对首尾进行操作,它的get方法做了部分优化,即index > size()/2 ? 尾部 : 首部

  • 在链表中使用for循环的方式遍历列表的效率 超低 ,如下:

    for(int i = 0; i < list.size(); i++)
        list.get(i);
    
  • hashMap中是无序的,当key相同时,会覆盖value

  • Set中判断重复是通过equals()hashCode(),所以把自定义类对象放到set中时要重写这两个方法

  • Tree主要是通过Comparator接口实现比较大小的,当排序不满足需求时需要重写

5. 转换

  • 集合和数组的相互转换

    String [] arr3 = list.toArray(new String[0]);   //当集合转换为数组时,数组长度小于等于集合的size时,转换后的数组长度等于size;否则和自己创建的空间一样大 
    
    List<String> li = Arrays.asList(arr);   //数组转换成集合
    
  • 数组和字符串的相互转换

    char [] arr = s.toCharArray();    //把字符串转换为char数组
    

6.迭代

不知道在看集合框架图的时候是否发现,有两个接口iterableIterator,我查阅API后发现,发现了一些区别:

  • Iterable和Iterator之间的异同

    • 前者在lang包,后者在util包不必多说
    • 分析两个单词的语义,前者表示“可迭代的”,后者表示“迭代器”。结合API,实现前者的类中都存在一个方法Iterator<T> iterator() 来获得迭代器,即Iterator
  • 当通过前者获得到后者之后,后者的方法中有三种比较常用:

    boolean	hasNext()	//Returns true if the iteration has more elements.
    E	next()	//Returns the next element in the iteration.
    default void	remove()	//Removes from the underlying collection the last element returned by this iterator (optional operation).
    
  • 迭代器的主要功能是用来遍历的,基本操作为:

    Set<T> se = new linkedSet<>();
    Iterator<T> it = se.iterator();	//ITerable可以换为任何一个实现此接口的方法
    while(it.hasNext()){
        System.println(it.next());
    }
    
  • foreach在底层就是调用的上述操作,换句话说,只要是实现了Iterable接口的类都可以用foreach语句:

    for(T e : se){
        do somthing with e;
    } 
    
  • JDK 8 之后甚至不需要用foreach,可以用到迭代器四个方法中的另外一个方法:

    default void	forEachRemaining(Consumer<? super E> action)	//为每个剩余元素执行给定的操作,直到处理完所有元素或操作引发异常为止。
        
    //我们可以这样来实现循环:
        iterator.forEachRemaining(e -> do some shit with e);
    
  • 因为Map接口没有继承迭代器,所以迭代Map时需要转换

      1. map中有keyset()方法可以获得key的集合并返回set,因为set实现了Iterable,所以可以遍历,如下:

                Set<String> keySet = map.keySet();  //获取key的集合
                Iterator<String> it = keySet.iterator();    //间接迭代
                while (it.hasNext()){
                    String key = it.next();
                    System.out.println(key + "..." + map.get(key));
                }
        //当然也可以通过foreach,此处不演示
        
      2. 因为map中是两个值之间的映射,如果把这两个值封装成一个对象,然后把对象封装在实现Iterable的集合中,再进行遍历,如下:

                //map.Entry说明Entry是map的内部接口,将键和值封装成了Entry对象,存储在set集合中
                Set<Map.Entry<String, Integer>> ent = map.entrySet();
                //获取每个对象
                //第一种用迭代器
                Iterator<Map.Entry<String, Integer>> it = ent.iterator();
                while(it.hasNext()){
                    Map.Entry<String, Integer> en = it.next();
                    System.out.println(en.getKey() + "..." + en.getValue());
                }
        
                //第二种,用foreach
                for (Map.Entry<String, Integer> e :
                     map.entrySet()) {
                        System.out.println(e.getKey() + "..." + e.getKey());
                }
        

7. 比较

主要观察Comparable和Comparator,因为treeset中二叉树判断大小中用到了这两个接口,所以也提一下

  • Comparable和Comparator两者之间的异同

    • 前者在lang包,几乎所有类都实现了此接口;后者在util包,是一个函数式接口;

    • 前者中只有一个方法,即compareTo(t,t),后者有多个,包括前者的方法

    • 因为第一条原因,所以自定义类通过实现前者的compareTo方法来比较,后者基本是用于构造方法。同时,后者的优先级大于前者。同时某些库类如String实现了前者,可以通过后者在构造方法中来覆盖。栗子如下:

      //Comparator
      		//1
      		//TreeSet<String> ts = new TreeSet<>(new compareByLen());
              // 按照这种比较器来比较,比较器优先级高,常用于已经重写Comparable接口,但是排序方式又不满足需求时
              //换种构造方法就可以使字符串安长度排序
      		class compareByLen implements Comparator<String> {
         		 @Override
         		 public int compare(String s1,String s2) {
              	int num = s1.length() - s2.length();
              	return num == 0 ? s1.compareTo(s2) : num;
          	}
      	    //因为此类继承了Object类,所以不用重写equals
      
      
              //2
              //此处可以用匿名内部类
              TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
                  @Override
                  public int compare(String o1, String o2) {
                      int num = o1.compareTo(o2);
                      return num == 0 ? 1 : num;  //不让它返回0就可保证不删除重复元素
                  }
              });
      
              //3
              //可以把内部类换成lambda
              TreeSet<String> ts = new TreeSet<>((s1, s2) -> {
                  int num = s1.compareTo(s2);
                  return num == 0 ? 1 : num;  //不让它返回0就可保证不删除重复元素
              });
      
      
      //Comparable
      public class Person implements Comparable<Person>{
      
          private int age;
          private String name;    
      	@Override
          public int compareTo(Person o) {
              return  (this.age - o.age) == 0 ? this.name.compareTo(o.name) : (this.age - o.age);
          }   //String中的compareTo方法已经重写,按照字典顺序进行排序
      }
      TreeSet<Person> p = new TreeSet<>();
      //这就可以完成对person类的排序
      

8. Collections

  • 属于util包下,该类完全由操作集合或返回集合的静态方法组成。它包含对集合进行操作的多态算法,“包装器”,它返回一个由指定集合支持的新集合,以及一些其他零碎内容。

  • 没有构造方法和子类,主要通过这个类的静态方法对集合进行操作。所以一般叫它“集合工具类”

  • Collection和Collections没有直接关系

  • 其中一些方法包括:

       		Collections.sort(list); //通过string中的compareTo方法进行排序
    
            System.out.println(Collections.binarySearch(list, "b"));    //返回-插入点-1
            System.out.println(Collections.binarySearch(list, "c"));	//二分查找
    
            System.out.println(Collections.max(list));  //获得最大值,即按照排序后的最大值
    
            Collections.reverse(list);      //翻转
    
            Collections.shuffle(list);      //对集合中所有的元素分配随机位置
    
  • 其余的方法需要大家查阅API

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值