Java笔记-集合框架

一、集合框架概述

1.引入集合框架

申明一个50长度的数组来存储数据的缺陷:

  1. 数组长度固定不变,不能很好地适应元素数量动态变化的情况。若要存储大于50个元素,则数组长度不足;若只存储20长度的数据,则造成内存空间浪费。
  2. 虽然可通过数组名.length获取数组的长度,却无法直接获取数组中真实存储的狗狗个数。
  3. 数组采用在内存中分配连续空间的存储方式,根据下标可以快速获取对应的信息,但是根据信息查找的时候效率低下,需要多次比较。在进行频繁插入、删除操作时同样效率低下。

2.Java集合框架包含的内容

Java集合框架为我们提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中。

集合框架包括三大块内容:对外接口、接口实现和对集合运算的算法

Java集合框架简图:

这里写图片描述

  • 接口:表示集合的抽象数据类型,如:Collection, List, Set, Map, Iterator
  • 实现:集合框架中接口的具体实现,如:ArrayList, LinkedList, HashMap, TreeMap, HashSet, TreeSet
  • 算法:在实现了的接口对象身上完成某种有用的计算方法,例如:查询、排序等。Java 提供了进行集合操作的工具类Collections (注意不是Collection),为我们提供了对集合进行排序等多种算法实现。使用时查看 JDK 帮助文档。

上图中可以看出Java 集合框架中的两大类接口:Collection 和 MapCollection又有两个子接口:List 和 Set。通常说Java集合框架共有三大类接口:List, Set 和 Map。共同点:都是集合接口,都可以用来存储很多对象。区别如下:

  • Collection接口存储一组不唯一(允许重复)、无序的对象。
  • Set接口继承Collection接口,存储一组唯一(不允许重复)、无序的对象。
  • List接口继承Collection接口,存储一组不唯一(允许重复)、有序(以元素插入的次序来放置元素,不会重新排列)的对象。
  • Map接口存储一组成对的键-值对象,提供key-value映射。key不要求有序,不允许重复。value同样不要求有序,但允许重复。
  • Iterator接口是负责定义访问和遍历元素的接口。

List可以理解为数组,元素内容可以重复并且有序。
Set可以理解为数学中的集合,数据不重复并且无序。

这里写图片描述

Map可以理解为数学中的集合,只是其中每个元素都由key-value两个对象组成。

这里写图片描述

二、List接口

ArrayList 对数组进行了封装,实现了长度可变的数组。ArrayList 存储数据的方式和数组相同,都是在内存中分配连续的空间,如下图。它的优点在于遍历元素和随机访问元素的效率比较高。

这里写图片描述

LinkedList 采用链表存储方式,如下图所示,优点在于插入、删除元素时效率比较高。他提供了额外的addFirst(), addLast(), removeFirst(), removeLast()等方法,这些方法使得 LinkedList 可被用作堆栈(stack)或者队列(queue)。

这里写图片描述

1.ArrayList集合类

ArrayList 接口中定义的各种常用方法如下表:

方法名称说明
boolean add(Object o)在列表末尾顺序添加元素,起始索引位置从0开始
void add(int index, Object o)在指定的索引位置添加元素,原索引位置及其后面的元素依次后移
注意:index∈[0, list.size()]
int size()返回列表中的元素个数
Object get(int index)返回指定索引位置处的元素
boolean contains(Object o)判断列表中是否存在指定元素
boolean remove(Object o)从列表中删除元素
Object remove(int index)从列表中删除指定位置元素
注意:index∈[0, list.size() - 1]

示例如下:

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

/**
 * @author 天道酬勤
 */
public class ArrayListDemo {
    public static void main(String[] args) {
        // 创建4个学生对象,Student类的属性:int age, String stuName
        Student s1 = new Student("s1", 18);
        Student s2 = new Student("s2", 17);
        Student s3 = new Student("s3", 16);
        Student s4 = new Student("s4", 15);
        // 创建ArrayList集合对象并把4个对象放入其中
        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        // 添加s4到下标为2的指定位置
        students.add(3, s4);
        // 输出集合中Student对象数量
        System.out.println("集合中共有" + 
            students.size() + "个Student对象");
        // 通过遍历集合显示各条信息
        System.out.println("初始Student信息:");
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            System.out.println(s.getStuName() + 
                "\t" + s.getAge());
        }
        // 删除下标为0的Student对象(第一条信息)
        students.remove(0);
        // 删除指定的Student对象
        students.remove(s4);
        // 显示删除后的列表信息
        System.out.println("删除后集合中共有" + 
            students.size() + "个Student对象");
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            System.out.println(s.getStuName() + 
                "\t" + s.getAge());
        }
        // 判断集合中是否包含指定的信息
        if (students.contains(s3)) {
            System.out.println("s3 is in ArrayList");
        } else {
            System.out.println("s3 is not in ArrayList");
        }

    }
}

运行结果如下图所示:

这里写图片描述

3.LinkedList集合类

LinkedList 除了上表中列出的各种方法外还包括一些特殊的方法,如下表所示:

方法名称说明
void addFirst(Object o)在列表的首部添加元素
void addLast(Object o)在列表的末尾添加元素
Object getFirst()返回列表中的第一个元素
Object getLast()返回列表中的最后一个元素
Object removeFirst()删除并返回列表中的第一个元素
Object removeLast()删除并返回列表中的最后一个元素

示例代码如下:

import java.util.LinkedList;

/**
 * @author 天道酬勤
 */
public class LinkedListDemo {
    public static void main(String[] args) {
        // 创建4个学生对象,Student类的属性:int age, String stuName
        Student s1 = new Student("s1", 18);
        Student s2 = new Student("s2", 17);
        Student s3 = new Student("s3", 16);
        Student s4 = new Student("s4", 15);
        // 创建LinkedList集合对象并把多个Student对象放入其中
        LinkedList<Student> students = new LinkedList<>();
        students.add(s1);
        students.add(s2);
        students.addFirst(s3);
        students.addLast(s4);
        // 查看第一个Student对象的名字
        System.out.println("第一个对象的stuName:" + 
            students.getFirst().getStuName());
        // 查看最后一个Student对象的名字
        System.out.println("最后一个对象的stuName:" + 
            students.getLast().getStuName());
        // 删除第一个Student对象和最后一个Student对象
        students.removeFirst();
        students.removeLast();
        // 显示删除后集合中的信息
        System.out.println("删除后的LinkedList信息");
        for (int i = 0; i < students.size(); i++) {
            System.out.println(students.get(i).getStuName() + 
                "\t" + students.get(i).getAge());
        }
    }
}

三、Set接口

Set 接口可以存储一组唯一、无序的对象。

常用实现类有HashSet

1.HashSet类动态存储数据

在数据量大的情况下,要查找某个数据,LinkedList 和 ArrayList 效率低下,前者由于数据结构决定效率底下,后者由于不知道下标,需要遍历一遍才可以。这时候我们需要HashSet。它实现了Set 接口,是使用 Set 集合的最常用的一个实现类。
HashSet特点如下:

  • 集合内的元素是无序排列的
  • HashSet 类是非线程安全的
  • 允许集合元素值为NULL

下表列出了 HashSet 类的常用方法:

方法说明
boolean add(Object o)如果此 Set 中尚未包含指定元素,则添加指定元素
void clear()从此 Set 中移除所有元素
int size()返回此 Set 中元素的数量(Set 的容量)
boolean isEmpty()如果此 Set 不包含任何元素,则返回true
boolean contains(Object o)如果此 Set 包含指定元素,则返回true
boolean remove(Object o)如果指定元素存在于此 Set 中,则将其移除

下面代码演示使用HashSet类常用方法存储并操作信息,并遍历集合,代码如下所示:

import java.util.HashSet;
import java.util.Set;

public class HashSetDemo {
    public static void main(String[] args) {
        Set<String> hs = new HashSet<>();
        for (int i = 0; i < 100; i++) {
            hs.add(Integer.toString(i));
        }
        for (String s : hs) {
            System.out.println(s);
        }
    }
}

该结果的部分运行结果如下所示(所以Set一组无序唯一的数据):
这里写图片描述

如果添加多次相同数据,则实际只添加了一次该数据:

import java.util.HashSet;
import java.util.Set;

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

运行结果如下所示:
这里写图片描述

注意
HashSet 不能使用(或者不推荐) 简单 for 循环遍历。
但是可以使用 Iterator 接口遍历,示例如下:

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetDemo {
    public static void main(String[] args) {
        Set<String> hs = new HashSet<>();
        for (int i = 0; i < 100; i++) {
            hs.add(Integer.toString(i));
        }
        Iterator<String> it = hs.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

运行结果与上面相同,无序唯一,在这里不演示了。

四、Map接口

Map 接口存储一组成对的键-值对象,提供key(键)到value (值)的映射。Map 中的 key 不要求有序,不允许重复。value 同样不要求有序,但允许重复。

最常用的Map 实现类是HashMap,它的存储方式是哈希表。哈希表也称为散列表,是根据关键码值(key value)而直接进行访问的数据结构。也就是说,他通过把关键码映射到表中一个位置来进行访问记录,以加快查找速度。存放记录的数组称为散列表。使用这种方式存储数据的优点是查询指定元素效率高

1.HashMap集合类

建立key-value对象,实现映射关系。如:CN->中华人民共和国,根据 “CN” 可以查找到 “中华人民共和国”,通过删除键可实现对应值的删除,存储和修改。

HashMap常用方法如下:

方法名称说明
Object put(Object key, Object value)以”键-值对”的方式进行存储。
注意:键必须是唯一的,值可以重复。如果试图添加重复的键,那么最后加入的”键-值对”将替换原先的”键-值对”。
Object get(Object key)根据键返回和关联的值,若不存在指定的键,则返回NULL
Object remove(Object key)删除指定的键映射的”键-值对”
int size()返回元素个数
Set keySet()返回键的集合
Collection values()返回值的集合
boolean containsKey(Object key)若存在指定的键映射的”键-值对”,则返回true
boolean isEmpty()若不存在键-值映射关系,则返回true
void clear()从此映射中移除所有映射关系

代码示例如下所示:

import java.util.HashMap;
import java.util.Map;

public class HashMapDemo {
    public static void main(String[] args) {
        // 使用HashMap存储多组国家英文简称和中文全称的"键-值对"
        Map<String, String> hmap = new HashMap<>();
        hmap.put("CN", "中华人民共和国");
        hmap.put("US", "美利坚合众国");
        hmap.put("RU", "俄罗斯联邦");
        hmap.put("FR", "法兰西共和国");
        // 显示"CN"对应国家的中文名称
        String country = hmap.get("CN");
        System.out.println(country);
        // 显示集合中元素的个数
        System.out.println("Map中共有:" + hmap.size() + "组数据");
        // 两次判断Map中是否存在"FR"值
        System.out.println("Map中包含FR的key吗?" 
            + hmap.containsKey("FR"));
        hmap.remove("FR");
        System.out.println("Map中包含FR的key吗?" 
            + hmap.containsKey("FR"));
        // 分别显示键集,值集和键-值对集
        System.out.println(hmap.keySet());
        System.out.println(hmap.values());
        System.out.println(hmap);
        // 清空HashMap并判断
        hmap.clear();
        if (hmap.isEmpty()) {
            System.out.println("已经清空HashMap中的数据!");
        }
    }
}

运行结果如下图所示:
这里写图片描述

五、迭代器Iterator

所有集合接口都没有提供相应的遍历方法,而是把遍历交给迭代器 Iterator 完成。 Iterator 为集合而生,专门实现集合的遍历。它隐藏了各种集合实现类的内部细节,提供了遍历集合的统一编程接口。

Collection 接口的 Iterator()方法返回一个 Iterator , 然后通过 Iterator 接口的两个方法即可方便的实现遍历。

  • boolean hasNext():判断是否存在另一个可访问的元素。
  • Object next():返回要访问的下一个元素。

1.使用Iterator遍历List集合类

用 Iterator 接口来遍历 List 中的元素(ArrayList 和 LinkedList):

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class IteratorList {
    public static void main(String[] args) {
        // ArrayList演示
        List<String> ls = new ArrayList<>();
        ls.add("1");
        ls.add("2");
        ls.add("3");
        ls.add("4");
        System.out.println("ArrayList中的所有数据:");
        Iterator<String> it = ls.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

        // LinkedList演示
        List<String> linkl = new LinkedList<>();
        linkl.add("7");
        linkl.add("8");
        linkl.add("9");
        linkl.add("10");
        System.out.println("\n");
        System.out.println("LinkedList中所有数据:");
        Iterator<String> linkl_it = linkl.iterator();
        while (linkl_it.hasNext()) {
            System.out.println(linkl_it.next());
        }
    }
}

运行结果如下:
这里写图片描述

2.使用Iterator遍历Map集合类

代码如下:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class IteratorMap {
    public static void main(String[] args) {
        // HashMap
        Map<String, String> map = new HashMap<>();
        map.put("1", "1");
        map.put("2", "2");
        map.put("3", "3");
        map.put("4", "4");
        Set<String> keys = map.keySet();
        Iterator<String> it = keys.iterator();
        while (it.hasNext()) {
            String key = it.next();
            System.out.println(map.get(key));
        }
    }
}

运行结果如下:
这里写图片描述

3.使用Foreach循环遍历Map集合

代码如下:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ForEachMap {
    public static void main(String[] args) {
        // HashMap
        Map<String, String> map = new HashMap<>();
        map.put("1", "1");
        map.put("2", "2");
        map.put("3", "3");
        map.put("4", "4");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(map.get(key));
        }
    }
}

运行结果如下:
这里写图片描述

3.使用Foreach循环遍历List集合

代码如下:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ForEachList {
    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<>();
        arrayList.add("1");
        arrayList.add("2");
        arrayList.add("3");
        arrayList.add("4");
        System.out.println("遍历arrayList结果:");
        for (String s : arrayList) {
            System.out.println(s);
        }
        List<String> linkedList = new LinkedList<>();
        linkedList.add("11");
        linkedList.add("22");
        linkedList.add("33");
        linkedList.add("44");
        System.out.println("遍历linkedList结果:");
        for (String s : linkedList) {
            System.out.println(s);
        }
    }
}

运行结果如下:
这里写图片描述

六、泛型集合

Collection 的 add(Object obj)方法的参数就是 Object 类型,无论把什么对象放入 Collection 及其子接口或实现类中,都认为只是 Object 类型,在通过 get(int index)方法取出集合中元素时必须进行强制类型转换,不仅繁琐且容易出现ClassCastException异常。Map 中使用put(Object key, Object value)get(Object key)方法存取对象时、使用 Iterator 的next()方法获取元素时也存在同样的问题。

JDK 1.5 中通过引用泛型(Generic)有效的解决了这个问题。在 JDK 1.5 中已经改写了集合框架中的所有接口和类,增加了对泛型的支持。

使用泛型集合在创建集合对象时指定集合中元素的类型,从集合中取出元素时无需进行类型强制转换,而且如果把非指定类型对象放入集合,会出现编译错误。

该页全部代码均使用了泛型集合,样式为:

//从左到右List为集合类型,
//StringList中存放的元素的引用数据类型或者对象
//(不可使用基本数据类型)
//右边的String可以不写
List<String> listName = new ArrayList<String>();
//Map同理,右边的<String, String>中的两个String要么都写,要么一个写
Map<String, String> mapName = new HashMap<String, String>();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值