java基础总结21-java集合

来源:互联网 发布:杭州淘宝网汽车拍卖 编辑:程序博客网 时间:2024/06/18 09:57

1 集合的由来及与数组的区别

集合类的由来:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类。

数组和集合类同的区别:

  • 数组可以存储同一种类型的基本数据也可以存储同一种类型的对象,但长度是固定的

  • 集合只可以存储不同类型的对象,长度是可变的

集合类的特点:集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

2 集合的继承体系图解

集合容器因为内部的数据结构不同,有多种具体容器,根据共性内容不断的向上抽取,就形成了集合框架。

框架的顶层Collection接口
这里写图片描述

3 Collection集合

Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

3.1 成员方法

  • boolean add(E e):确保此 collection 包含指定的元素(可选操作)。

  • boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。

  • void clear():移除此 collection 中的所有元素(可选操作)。

  • boolean contains(Object o):如果此 collection 包含指定的元素,则返回 true。

  • boolean isEmpty():如果此 collection 不包含元素,则返回 true。

  • int size():返回此 collection 中的元素数。

例:

// 创建集合对象// Collection c = new Collection(); //错误,因为接口不能实例化Collection c = new ArrayList();c.add("hello");c.add("world");c.add("java");// c.clear();//移除所有元素// System.out.println("remove:" + c.remove("hello"));//移除一个元素// System.out.println("remove:" + c.remove("javaee"));// 判断集合中是否包含指定的元素 System.out.println("contains:"+c.contains("hello"));//contains:true System.out.println("contains:"+c.contains("android"));//contains:false //判断集合是否为空 System.out.println("isEmpty:"+c.isEmpty());//isEmpty:false//元素的个数System.out.println("size:"+c.size());//size:3System.out.println("c:" + c);//c:[hello, world, java]
高级功能成员方法:1.  boolean addAll(Collection<? extends E> c):将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。2.  boolean removeAll(Collection<?> c):移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。3.  boolean containsAll(Collection<?> c):如果此 collection 包含指定 collection 中的所有元素,则返回 true4.  boolean retainAll(Collection<?> c):仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。换句话说,移除此 collection 中未包含在指定 collection 中的所有元素。

例:

c1.addAll(c2);//将c2集合中的所有元素添加到c1集合中,c1变c2不变c1.removeAll(c2);//将c1集合中与c2集合相同的所有元素删除,只要有一个相同的就返回truec1.containsAll(c2);//判断c1集合中的元素是否包含c2中的全部元素,全部包含则返回truec1.retainAll(c2);//将c1集合中与c2集合相同的元素保留,删除其他元素,返回值表示c1集合是否发生变化,发生变化返回true,没有变化返回false

3.2 集合的遍历

集合的遍历之集合转数组遍历

Object[] toArray():返回包含此 collection 中所有元素的数组。

例:

public class Practice {    public static void main(String[] args)    {        // 创建集合        Collection c = new ArrayList();        c.add("hello");        c.add("world");        c.add("java");        Object[] objs = c.toArray();        for (int i = 0; i < objs.length; i++)         {            //向下转为String类型            String s = (String)objs[i];            System.out.println(s+":"+s.length());        }    }}

运行结果:

hello:5world:5java:4

集合的遍历之迭代器遍历

Iterator iterator():返回在此 collection 的元素上进行迭代的迭代器。

例:

// 创建集合Collection c = new ArrayList();//创建元素并添加到集合c.add("hello");c.add("world");c.add("java");//获取迭代器,实际返回的是子类对象,多态Iterator it = c.iterator();while(it.hasNext()){    System.out.println(it.next());}

迭代器使用的问题探讨

  • 使用迭代器获取元素的两种方式:
    方式1:
Iterator it = c.iterator();while(it.hasNext()){   Student s = (Student)it.next();   System.out.println(s.getName()+":"+s.getAge());}

方式2:

for(Iterator it = c.iterator();it.hasNext();){   Student s = (Student)it.next();   System.out.println(s.getName()+":"+s.getAge());}

使用方式2的好处:it在for循环结束后就变成垃圾,效率较高

  • 不要多次使用it.next()方法
    例:
Iterator it = c.iterator();while(it.hasNext()){   System.out.println(((Student)it.next()).getName());   System.out.println(((Student)it.next()).getAge());}

上面的代码表示获取的是第1个学生的姓名,第2个学生的年龄,以此类推,如果集合中的元素是奇数个,则会报NoSuchElementException错误

3.3 集合的使用步骤图解

这里写图片描述
集合的使用步骤:

  1. 创建集合对象

  2. 创建元素对象

  3. 将元素添加到集合

  4. 遍历集合

        4.1 通过集合对象获取迭代器对象

        4.2 通过迭代器对象的hasNext()方法判断是否有元素

        4.3 通过迭代器对象的Next()方法获取元素并移动到下一个位置

3.4 Collection存储学生对象并遍历

import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;public class Practice {    public static void main(String[] args)    {        // 创建集合        Collection c = new ArrayList();        //创建学生对象并添加到集合        c.add(new Student("小明",23));        c.add(new Student("小红",32));        c.add(new Student("小强",14));        c.add(new Student("旺财",8));        c.add(new Student("张三",16));        Iterator it = c.iterator();        while(it.hasNext())        {            Student s = (Student)it.next();            System.out.println(s.getName()+":"+s.getAge());        }    }}

4 List集合

List接口概述:有序的(存取顺序一致)collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

特点:与 set 不同,列表通常允许重复的元素。

4.1 List集合的特有功能

1.  void add(int index,E element):在列表的指定位置插入指定元素(可选操作)。2.  E remove(int index):移除列表中指定位置的元素(可选操作)。3.  E get(int index):返回列表中指定位置的元素。4.  E set(int index, E element):用指定元素替换列表中指定位置的元素(可选操作)。例:list.add(2,"javaee");//在2的位置插入javaee,改变集合长度list.get(2)//返回集合中2位置上的元素,不改变集合长度list.remove(1)//删除集合中1位置上的元素,返回被删除的元素,改变集合长度list.set(2, "javaee")//将集合中2位置上的元素替换为javaee,返回被替换的元素,不改变集合长度

4.2 List存储学生对象并遍历

public class Practice {    public static void main(String[] args)    {        // 创建集合        List list = new ArrayList();        //创建学生对象并添加到集合        list.add(new Student("小明",23));        list.add(new Student("小红",32));        list.add(new Student("小强",14));        list.add(new Student("旺财",8));        list.add(new Student("张三",16));        Iterator it = list.iterator();        while(it.hasNext())        {            Student s = (Student)it.next();            System.out.println(s.getName()+":"+s.getAge());        }    }}

4.3 List的三个子类的特点

  • ArrayList:底层数据结构是数组,查询快,增删慢,是不同步的,线程不安全,效率高

  • Vector:底层数据结构是数组,查询快,增删慢,是同步的,线程安全,效率低

  • LinkedList:底层数据结构是链表,查询慢,增删快,是不同步的,线程不安全,效率高

5 Set集合

Set接口概述:一个不包含重复元素的 collection

特点:

  • 无序(存入与取出的顺序不一致)

  • 唯一(存入集合的元素唯一)

5.1 HashSet

HashSet存储字符串并遍历

HashSet类概述:不保证 set 的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

例:

public class Practice {    public static void main(String[] args)    {        HashSet<String> hs = new HashSet<String>();        hs.add("hello");        hs.add("world");        hs.add("world");        hs.add("java");        for (String s : hs)         {            System.out.println(s);        }    }}

运行结果:

hellojavaworld

HashSet保证元素唯一性的源码解析

interface Collection{...}interface Set extends Collection {...}class HashSet implements Set {    private static final Object PRESENT = new Object();    private transient HashMap<E,Object> map;    public HashSet()     {        map = new HashMap<>();    }    public boolean add(E e)     { //e=hello,world        return map.put(e, PRESENT)==null;    }}class HashMap implements Map {    public V put(K key, V value)     { //key=e=hello,world        //看哈希表是否为空,如果空,就开辟空间        if (table == EMPTY_TABLE)         {            inflateTable(threshold);        }        //判断对象是否为null        if (key == null)            return putForNullKey(value);        int hash = hash(key); //和对象的hashCode()方法相关        //在哈希表中查找hash值        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next)         {            //这次的e其实是第一次的world            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))             {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;                //走这里其实是没有添加元素            }        }        modCount++;        addEntry(hash, key, value, i); //把元素添加        return null;    }    transient int hashSeed = 0;    final int hash(Object k)     { //k=key=e=hello,        int h = hashSeed;        if (0 != h && k instanceof String)         {            return sun.misc.Hashing.stringHash32((String) k);        }        h ^= k.hashCode(); //这里调用的是对象的hashCode()方法        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }}

通过查看add方法的源码,知道这个方法底层依赖两个方法:hashCode()和equals()。

判断元素唯一性的方式:通过对象的hashCode和equals方法来完成元素唯一性

  • 如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。
  • 如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。
  • 如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。

如果类没有重写这两个方法,默认使用的Object()。一般来说不会相同。

5.2 TreeSet

TreeSet类概述:使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。

所以,要想重写该方法,就必须是先实现 Comparable接口。这个接口表示的就是自然排序。

TreeSet对元素排序的总结

唯一性:根据比较的返回的是否是0来决定
排序:

  • 自然排序,一个类的元素想要进行自然排序就必须实现自然排序接口Comparable(元素具备比较性)

  • 比较器排序,让集合的构造方法接收一个比较器接口的子类对象Comparator(集合具备比较性)

6 Map集合

6.1 Map集合概述和特点

Map接口概述:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值

Map接口和Collection接口的不同

1.Map是双列的,Collection是单列的

2.Map的键唯一,Collection的子体系Set是唯一的

3.Map集合的数据结构值针对键有效,跟值无关,Collection集合的数据结构是针对元素有效

6.2 Map集合的功能概述

成员方法:1.V put(K key,V value):将指定的值与此映射中的指定键关联(可选操作)。2.V remove(Object key):如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。3.void clear():从此映射中移除所有映射关系(可选操作)。4.boolean containsKey(Object key):如果此映射包含指定键的映射关系,则返回 true5.boolean containsValue(Object value):如果此映射将一个或多个键映射到指定值,则返回 true6.boolean isEmpty():如果此映射未包含键-值映射关系,则返回 true7.int size():返回此映射中的键-值映射关系数。8.V get(Object key)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。9.Set<K> keySet()返回此映射中包含的键的 Set 视图。10.Collection<V> values()返回此映射中包含的值的 Collection 视图。11.Set<Map.Entry<K,V>> entrySet()返回此映射中包含的映射关系的 Set 视图。

6.3 Map集合的基本功能测试

map.put(“001”, “旺财”); :第一次存储直接存储元素,返回null

map.put(“001”, “小强”); :不是第一次存储,用新值将以前的值替换掉,返回以前的值

map.remove(“001”); :根据键删除键值对元素,并返回键所对应的值,没有则返回空

6.4 Map集合的获取功能测试

Map<String, String> map = new HashMap<String, String>();map.put("001", "小明");map.put("002", "旺财");map.put("003", "小强");//根据键获取值System.out.println(map.get("002"));//旺财,没有该键返回nullSystem.out.println("-----");//获取集合中所有键的集合Set<String> set = map.keySet();for(String key : set){    System.out.println(key);}System.out.println("-----");//获取集合中所有值的集合Collection<String> coll = map.values();for(String value : coll){    System.out.println(value);}

6.5 Map集合的遍历之键找值

根据键找值:

获取所有键的集合,遍历键的集合,获取到每一个键,根据键找值

Map<String, String> map = new HashMap<String, String>();map.put("001", "小明");map.put("002", "旺财");map.put("003", "小强");//获取所有的键Set<String> set = map.keySet();for(String key : set){    //根据键找值    String value = map.get(key);    System.out.println(key+":"+value);}

6.6 Map集合的遍历之键值对对象找键和值

根据键值对对象找键和值:

获取所有键值对对象的集合,遍历键值对对象的集合,获取到每一个键值对对象,根据键值对对象找键和值

Map<String, String> map = new HashMap<String, String>();map.put("001", "小明");map.put("002", "旺财");map.put("003", "小强");//获取所有键值对对象的集合Set<Map.Entry<String, String>> set = map.entrySet();//遍历键值对对象的集合,获取每一个键值对对象for(Map.Entry<String, String> me : set){    //根据键值对对象获取键和值    String key = me.getKey();    String value = me.getValue();    System.out.println(key+":"+value);}

7 集合总结

这里写图片描述

7.1 判断元素唯一性

HashSet、HashMap、Hashtable判断元素唯一性的方式:

通过对象的hashCode和equals方法来完成元素唯一性

如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。

如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。

如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。

最终:自动生成hashCode()和equals()即可

TreeSet、TreeMap判断元素唯一性的方式:根据比较的返回的是否是0来决定

7.2 TreeSet排序

1.自然排序,一个类的元素想要进行自然排序就必须实现自然排序接口Comparable(元素具备比较性)

2.比较器排序,让集合的构造方法接收一个比较器接口的子类对象Comparator(集合具备比较性)

7.3 如何选择使用哪种集合

这里写图片描述

7.4 集合常见功能和遍历方式

集合的常见方法及遍历方式

Collection:add()、remove()、contains()、iterator()、size()

遍历:增强for、迭代器

Collection子类List:get()

遍历:普通for

Collection子类Set

Map:put()、remove()、containskey()、containsValue()、keySet()、get()、value()、entrySet()、size()

遍历:根据键找值、根据键值对对象分别找键和值

8 集合面试题

8.1 Hashtable和HashMap的区别

Hashtable:线程安全,效率低。不允许null键和null值

HashMap:线程不安全,效率高。允许null键和null值

8.2 List,Set,Map等接口是否都继承子Map接口?

List,Set不是继承自Map接口,它们继承自Collection接口

Map接口本身就是一个顶层接口

0 0
原创粉丝点击