java集合框架

java集合框架

1.集合框架的由来

1.1什么是集合框架?

集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法.

1.2为什么要有集合框架?

其实在java2之前,java是没有完整的集合框架的,只有一些简答的容器类比如Vector类、Stack类,HashTable类等等。容器类就是用来存储数据。这里数据只能是引用类型的数据,当然,一说到存储数据很快我们会想到数组,数组是可以存储相同类型,可以是基本类型,也可以是引用类型。

数组也存在很多的弊端:

  • 数组一旦初始化,长度是固定的,不能再改变了。
  • 每次使用都得编写操作数组的方法,体现不了java的封装思想。

java把集合框架的类和接口都放在了java.util包中

2.集合体系

1296856-20181022171945228-2107744205.png
1296856-20181022172425913-1918036121.png
1296856-20181022172440419-992080662.png

3.List接口

Collection是存储数据的容器。

1296856-20181022172515956-185831603.png

常用操作方法


增加:
boolean add(Object e) 将指定元素添加到此向量的末尾,等价于addElement方法。 
void add(int index, Object element)  在此向量的指定位置插入指定的元素。 
boolean addAll(Collection c) :把c集合中的元素添加到当前集合对象中.

删除:
Object remove(int index) :删除指定索引位置的元素,并返回删除之后的元素.
boolean remove(Object o):删除指定的元素.
boolean removeAll(Collection c):从此集合中移除包含在指定 集合c中的所有元素。 
boolean retainAll(Collection c):在此集合中仅保留包含在指定 集合c中的元素,求两个集合的交集。 

修改:
Object set(int index, Object element) :修改当前集合中指定索引位置的元素.
                   返回被替换的旧的元素.

查询:
int size()  :返回当前集合中存储几个元素.
boolean isEmpty():判断当前集合中元素个数是否为0. 
Object  get(int index):查询指定索引位置的元素.
Object[] toArray():把集合对象转换为Object数组.

3.1Vector类

集合框架出现之前,有一个容器类就是Vector类,Vector类的底层其实就是一个Object数组 protected Object [] elementData;

Vector类现在已经基本上被ArrayList取代了

3.1.1Vector类的存储原理
  • 底层是一个Object类型的数组,所以可以存储任意类型的对象,注意:集合中只能存储对象,不能存储基本类型的数据。但是java5之后支持了自动装箱操作,可以基本类型的值自动装箱为包装类型,但也存储的是对象.
  • 集合中存储的对象,都是存储的是对象的引用,并不是对象的本身.如下:
        Vector v2 = new Vector();
        StringBuilder sb = new StringBuilder("SSSS");
        v2.add(sb);//集合类中存储的对象,存储的是对象的引用,并不是存储的值
        System.out.println(v2);//SSSS
        sb.append(222);
        System.out.println(v2);//SSSS222

3.2Stack类

Stack是数据结构的一种,先进先出原则,Stack类继承于Vector类,底层可以用数组存储,也可以用链表来存储,官方建议使用ArrayQueue

Deque 接口及其实现提供了 LIFO 堆栈操作的更完整和更一致的 set,应该优先使用此 set,而非此类。例如: 

   Deque<Integer> stack = new ArrayDeque<Integer>();

3.3ArrayList类

ArrayList类是Java集合框架出现之后用来取代Vector类的。二者底层原理都是基于数组的算法,一模一样.

区别

  • Vector: 所有的方法都使用了synchronized修饰符. 线程安全但是性能较低. 适用于多线程环境.

  • ArrayList:所有的方法都没有使用synchronized修饰符. 线程不安全但是性能较高.

  • 即使以后在多线程环境下,我们也不使用Vector类: ArrayList list = Collections.synchronizedList(new ArrayList(...));

    在Java7之前,即使使用new ArrayList创建对象,一个元素都不存储,但是在堆空间依然初始化了长度位10的Object数组,没必要. 从Java7开始优化这个设计,new ArrayList,其实底层创建的使用一个空数组. Object [] elementData = new Object[]{}; 在第一次调用add方法的时候,才会重新去初始化数组.

3.4 LinkedList类

LinkedList类是双向链表,单向链表双向队列和栈 的实现类

优势:无论是链表还是队列,它们都擅长操作头和尾,所以在LinkedList中的大多数方法都是xxFirst()

看API会发现,LinkedList中依然存在get(int index)方法,也就是根据索引来确定存储的值,链表中是没有索引的概念的,之所以有这个方法是因为有了集合框架,让LinkedList作为了List接口的实现,没法发只能来实现这个方法,我们也该少用这个方法

3.5List接口实现类比较

面向接口编程:

接口类型  变量 =   new  实现类();List      list = new ArrayList();

三者共同的特点(共同遵循的规范):

  • 1):允许元素重复.
  • 2):记录元素的先后添加顺序.
  • Vector类: 底层采用数组结构算法,方法都使用了synchronized修饰,线程安全,但是性能相对于ArrayList较低.
  • ArrayList类: 底层采用数组结构算法,方法没有使用synchronized修饰,线程不安全,性能相对于Vector较高.ArrayList现在机会已经取代了Vector,为了保证ArrayList的线程安全,List list = Collections.synchronizedList(new ArrayList(...));

4.Set接口

Set是Collection子接口,模拟了数学上的集的概念。

特点:

  • 不允许元素重复
  • 不会记录元素的添加顺序

Set判断两个对象是否相等用equals,而不是使用==。也就是说两个对象equals比较返回true,Set集合是不会接受这个两个对象的。

4.1HashSet类

HashSet是Set接口最常用的一个类,底层采用的是哈希表算法

在HashSet中如何判断两个对象相同?

当往集合中添加新的对象,先判断该对象和集合对象中的HashCode值:

  • 不等,直接把该对象存储到HashCode 指定的位置
  • 相等,在据需判断新的对象和集合中的equals比较

二者缺一不可

每一个存储到hash表中的对象,都得提供hashCode和equals方法,用来判断是否是同一个对象.存储在哈希表中的对象,都应该覆盖equals方法和hashCode方法,并且保证equals相等的时候,hashCode也应该相等.

4.2LinkedHashSet类

顾名思义,底层用的是链表和哈希表算法,链表记录元素的添加顺序,哈希表保证元素不重复。。综合了List接口和Set接口的特点,很强势,但是性能并不高

LinkedHashSet类是HashSet类的子类

4.3TreeSet类

底层采用的是红黑树算法,会对存储的元素默认进行自然排序,从小到大。

  • 自然排序

TreeSet调用集合元素的compareTo方法来比较元素的大小关系,然后讲集合元素按照升序排列(从小到大).注意:要求TreeSet集合中元素得实现java.util.Comparable接口.覆盖 public int compareTo(Object o)方法,在该方法中编写比较规则.在该方法中,比较当前对象(this)和参数对象o做比较(严格上说比较的是对象中的数据). this > o: 返回正整数. 1 this < o: 返回负整数. -1 this == o: 返回0. 此时认为两个对象为同一个对象.

  • 定制排序

在创建对象的时候,在TreeSet构造器中传递java.lang.Comparator对象.并覆盖public int compare(Object o1, Object o2)再编写比较规则.

package set;
import java.util.*;
/**
 * @author 15626
 *  TreeSet 底层采用的是是红黑树算法,会对存储的 元素进行自然排序(从小到大)
 *  要排序当然要保证类型相同,可以使用泛型进行规范
 *  排序规则:数字就进行比大小,字符就按照Unicode编码规范来比较(前128位与ASCII编码重复)
 */
public class TreeSetDemo {

    public static void main(String []args){
        Set<Student> set = new TreeSet<Student>();
        set.add(new Student("张三",30));
        set.add(new Student("李四",20));
        set.add(new Student("王麻子",10));
        System.out.println(set);
        
        
        /**
         * 定制排序:在TreeSet构造器中传一个实现Comparator接口类的一个对象,
         * 在实现类中覆盖Comparator接口中的public int compare(Ojbect o1,Object o2)方法
         * 在方法中可以编写比较规则 
         */
        
        //定制排序:根据人名长度进行排序
        Set<Student> set2 = new TreeSet<Student>(new NameLengthComparator());
        set2.add(new Student("张三李四",30));
        set2.add(new Student("李四",20));
        set2.add(new Student("王麻子",10));
        System.out.println(set2);
    }
}
class NameLengthComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        // TODO Auto-generated method stub
        if(o1.name.length()>o2.name.length()){
            return 1;
        }else if(o1.name.length() < o2.name.length()){
            return -1;
        }else{
            return 0;    //说明是同一个对象
        }
    }
    
}
class Student implements Comparable<Student>{
    String name;
    int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    /* 自然排序:覆盖Comparable接口中的compareTo方法
     * this > o ,返回正整数
     * this < o ,返回负整数
     * this = o ,返回0     //说明两个对象相同
     * 
     */

    @Override
    //自然排序:根据年龄排序
    
    public int compareTo(Student o) {
        if(this.age > o.age){
            return 1;      
        }else if(this.age < o.age){
            return -1;
        }
        return 0;
    }
}

4.4 Set实现类的比较

共同点:

  • 都不允许元素重复
  • 都不是线程安全的类

不同:

  • HashSet 不保证元素的先后添加顺序.底层采用的是哈希表算法,查询效率极高.
    • 判断两个对象是否相等的规则:
      • equals比较为true
      • hashCode值相同.
      • 要求存在在哈希中的对象元素都得覆盖equals和hashCode方法.
  • LinkedHashSet HashSet的子类,底层也采用的是哈希表算法,但是也使用了链表算法来维持元素的先后添加顺序.
    • 判断两个对象是否相等的规则和HashSet相同. 因为需要多使用一个链表俩记录元素的顺序,所以性能相对于HashSet较低.
  • TreeSet 不保证元素的先后添加顺序,但是会对集合中的元素做排序操作,底层采用红黑树算法
    • 自然排序: 要求在TreeSet集合中的对象必须实现java.lang.Comparable接口,并覆盖compareTo方法.
    • 定制排序: 要求在构建TreeSet对象的时候,传入一个比较器对象(必须实现java.lang.Comparator接口). 在比较器中覆盖compare方法,并编写比较规则.
    • TreeSet判断元素对象重复的规则: compareTo/compare方法是否返回0.如果返回0,则视为是同一个对象.

5.Map接口

严格上说,Map并不是集合,而是两个集合之间的映射关系(Map接口并没有继承于Collection接口),然而因为Map可以存储数据(每次存储都应该存储A集合中以一个元素(key),B集合中一个元素(value)),我们还是习惯把Map也称之为集合.

Map接口并没有继承于Collection接口也没有继承于Iterable接口,所以不能直接对Map使用for-each操作.

  • 可以把Map中的key看做一个Set集合(不允许重复)
  • 可以吧Map中的value看做一个List集合(允许重复)
  • 可以把Entry(key-value)键值对看做一个Set集合(不允许重复)

如此以来,可以间接的对Map使用for-each

其实,相同算法的Set底层用的是相同算法的Map. 把Set的集合对象作为Map的key,再使用一个Object常量做为value.

5.1Map的常用方法

 void clear() 
          从此映射中移除所有映射关系(可选操作)。 
 boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 true。 
 boolean containsValue(Object value) 
          如果此映射将一个或多个键映射到指定值,则返回 true。 
 Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。 
 boolean equals(Object o) 
          比较指定的对象与此映射是否相等。 
 V get(Object key) 
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 
 int hashCode() 
          返回此映射的哈希码值。 
 boolean isEmpty() 
          如果此映射未包含键-值映射关系,则返回 true。 
 Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。 
 V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。 
 void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。 
 V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 
 int size() 
          返回此映射中的键-值映射关系数。 
 Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。 

5.2HashMap类

采用哈希表算法, 此时Map中的key不会保证添加的先后顺序,key也不允许重复.

key判断重复的标准是: key1和key2是否equals为true,并且hashCode相等.

5.3TreeMap类

采用红黑树算法,此时Map中的key会按照自然顺序或定制排序进行排序,,key也不允许重复. key判断重复的标准是: compareTo/compare的返回值是否为0.

5.4 LinkedHashMap类

采用链表和哈希表算法,此时Map中的key会保证先后添加的顺序,key不允许重复.

key判断重复的标准和HashMap中的key的标准相同.

5.5 Hashtable类

采用哈希表算法,是HashMap的前身(类似于Vector是ArrayList的前身)

在Java的集合框架之前,表示映射关系就使用Hashtable.

HashMap和TreeMap以及LinkedHashMap都是线程不安全的,但是性能较高。

解决方案: Map m = Collections.synchronizedMap(Map对象);

6.集合工具类

6.1 Arrays类

在Collection接口中有一个方法叫toArray把集合转换为Object数组. 把集合转换为数组: Object[] arr = 集合对象.toArray();

数组也可以转换为集合(List集合): public static List asList(T... a) 等价于public static List asList(T[] a).

package util;

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author 15626
 *  集合的工具类 :Arrays,可以把数组转换成集合
 */
public class ArraysDemo {
    public static void main(String []args){
        //把集合转换成数组
        ArrayList<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("d");
        Object [] arr= list.toArray();
        for(Object arr1 : arr){
            System.out.println(arr1);
        }
        
        System.out.println("========================");
        
        //把数组转化成集合
        String [] str = new String[]{"A","b","C"};
        
        //返回的是不能改变长度的list对象,因为返回的ArrayList不是java.util.ArrayList包中的对象,而是Arrays类中的内部类对象
        List<String> list2 = Arrays.asList(str);
        //list2.remove(0);//UnsupportedOperationExceptions
        System.out.println(list2);
        
        //基本类型的数据会自动装箱转化为包装类型,这里的1,2,3都自动装箱为Integer类型
        List<Integer> list3 = Arrays.asList(1,2,3,4,5);
        System.out.println(list3);
        
        //试图把数组直接转化一下,这是直接把数组当做对象,基本类型的数据不能存储到集合中
        int [] a = new int[]{1,2,3,4,5};
        List<int[]> list4 = Arrays.asList(a);
        System.out.println(list4);
    }
}

6.2Collections类

HashSet/ArrayList/HashMap都是线程不安全的,在多线程环境下不安全. 在Collections类中有获取线程安全的集合方法:

Set  set = Collections.synchronizedSet(new HashSet());
Map  map = Collections.synchronizedMap(new HashMap());
List list = Collections.synchronizedList(new ArrayList());

7.泛型

集合框架牵扯到了泛型,这有篇文章对泛型有很详细的解释:https://www.cnblogs.com/coprince/p/8603492.html

8.测试代码

https://github.com/EarthSoar/JavaExamples/tree/master/CollectionsFramework

转载于:https://www.cnblogs.com/tfper/p/9831252.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值