Java 基础 -- 集合框架

集合

1. Java集合框架

1.1 简介

  • Java类库中, 集合类的基本接口是: Collection接口和Map接口
  • Collection是元素集合, Map是键值对(key-value)
  • Collection接口有两个基本两个方法:
    • boolean add(E element); 向集合中添加元素
    • Iterator iterator(); 返回一个迭代器, 用于访问集合中的对象
  • Iterator接口中有两个常用方法:
    • E next(); 反复调用可以逐个访问集合中每个元素
    • boolean hasNext(); 判断是否还有元素, 用在调用next() 方法之前
  • Map接口常用方法:
    • V put(K key, V value);
    • V get(K key);

1.2 Collection常用方法:

  • int size();
  • boolean isEmpty();
  • boolean contains(Object o);
  • boolean containsAll(Collection c);
  • boolean add(Object o);
  • boolean addAll(Collection

1.3 Iterator常用方法

  • boolean hasNext(); 判断是否还存在可访问的元素
  • E next(); 返回将要访问的下一个对象, 如果已经到达集合尾部, 会抛出: NoSuchElementException
  • void remove(); 删除上次访问的对象, 必须紧跟在next()方法后

2. 具体的集合: 主要是以下接口的实现

  • List: 序列
  • Set: 集
  • Map: 字典

2.1 常用的具体集合

  • ArrayList: 可以动态增长和缩减的索引序列
  • LinkedList: 一种可以在任何位置进行高效插入删除的有序序列
  • HashSet: 没有重复元素的无序集合
  • TreeSet: 一种有序集
  • HashMap: 一种存储 键值对的数据结构
  • TreeMap: 一种有序排列的键值对表

2.2 List的分析:

  • ArrayList: 基于数组实现, 数组存在索引, 所以查询和更改效率高, 删除和指定位置添加效率低
  • LinkedList: 基于双向链表实现, 删除和添加元素效率高, 查询和更改效率低
  • Vector: 线程安全的ArrayList, 在同步操作上会耗费大量时间
  • 示例代码:
package cn.kuang.java_primary.collection;

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

/**
 * 1. 简单的创建两个链表, 合并在一起
 *
 * 2. 从第二个链表每隔一个元素删除一个元素
 *
 * 3. 绘制一个迭代器位置示意图
 *
 * Created by 框 on 2018/6/18.
 */
public class LinkedListTest {

    public static void main(String[] args) {

        // create linkedList a and b
        List<String> a = new LinkedList<>();
        a.add("tom");
        a.add("bob");
        a.add("amy");

        List<String> b = new LinkedList<>();
        b.add("Carl");
        b.add("doug");
        b.add("france");
        b.add("eric");

        System.out.println(a);
        System.out.println(b);

        //merge the words from b into a
        ListIterator<String> aIter = a.listIterator();
        Iterator<String> bIter = b.iterator();

        while (bIter.hasNext()){
            if (aIter.hasNext()) aIter.next();
            aIter.add(bIter.next());
        }

        System.out.println(a);

        //remove every second word from b
        bIter = b.iterator();
        while (bIter.hasNext()){
            bIter.next();
            if (bIter.hasNext()){
                bIter.next();
                bIter.remove();
            }
        }

        System.out.println(b);

        //bulk operation : remove all words in b from a
        a.removeAll(b);
        System.out.println(a);

    }

}

2.3 Set的分析:

  • 不在意元素的顺序, 可以快速查找到元素
  • 散列表: 为每个对象调用HashCode返回一个散列码,
  • 常用HashSet, 实现基于散列表的集
  • HashSet特点: 无序, 没有重复元素
  • 示例代码:
package cn.kuang.java_primary.collection;

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

/**
 * 1. 从System.in读取单词
 *
 * 2. 把他们添加到HashSet中
 *
 * 3. 遍历HashSet中的不同单词
 *
 * 4. 打印出单词数量
 *
 * Created by 框 on 2018/6/19.
 */
public class SetTest {
    public static void main(String[] args) {

        Set<String> words = new HashSet<>();
        long totalTime = 0;

        try(Scanner in = new Scanner(System.in);) {
            while (in.hasNext()){
                String word = in.next();
                long callTime = System.currentTimeMillis();
                words.add(word);
                callTime = System.currentTimeMillis() - callTime;
                totalTime += callTime;
            }
        }

        Iterator<String> iter = words.iterator();
        for (int i = 0; i < 20 && iter.hasNext(); i++) {
            System.out.println(iter.next());
        }

        System.out.println("......");
        System.out.println(words.size() + " distinct words. " + totalTime + " milliseconds");

    }
}
  • TreeSet: 是一个有序的集合, 使用红黑树实现
  • TreeSet特点: 添加元素比HashSet慢, 但是元素有序, 任意两个元素必须是可比的
  • 示例代码:
package cn.kuang.java_primary.collection.pojo;

import java.util.Objects;

/**
 * Item 实体类
 *
 * Created by 框 on 2018/6/19.
 */
public class Item implements Comparable<Item> {

    private String description;
    private int partNumber;

    /**
     * 有参构造器
     * @param description description
     * @param partNumber partNumber
     */
    public Item(String description, int partNumber) {
        this.description = description;
        this.partNumber = partNumber;
    }

    /**
     * Gets of description
     * @return description
     */
    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return "Item[" + "description='" + description + '\'' + ", partNumber=" + partNumber + ']';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Item)) return false;

        Item item = (Item) o;

        if (partNumber != item.partNumber) return false;
        return description != null ? description.equals(item.description) : item.description == null;
    }

    @Override
    public int hashCode() {
        return Objects.hash(description, partNumber);
    }

    @Override
    public int compareTo(Item o) {
        int diff = Integer.compare(partNumber, o.partNumber);
        return diff != 0 ? diff : description.compareTo(o.description);
    }
}

--------------------------------------------------------------------------
package cn.kuang.java_primary.collection;

import cn.kuang.java_primary.collection.pojo.Item;

import java.util.Comparator;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 * 1. 创建两个Item对象的树集
 *
 * 2. 第一个按照部件编号排序: Item对象的默认顺序
 *
 * 3. 第二个通过一个定制的比较器按照描述信息排序
 *
 * Created by 框 on 2018/6/19.
 */
public class TreeSetTest {
    public static void main(String[] args) {
        SortedSet<Item> parts = new TreeSet<>();
        parts.add(new Item("Toaster", 1234));
        parts.add(new Item("Widget", 4562));
        parts.add(new Item("Modem", 9912));
        System.out.println(parts);

        NavigableSet<Item> sortByDescription = new TreeSet<>(Comparator.comparing(Item::getDescription));

        sortByDescription.addAll(parts);
        System.out.println(sortByDescription);

    }
}

3. 映射/字典

3.1 基本映射操作

  • Java类库提供了两个通用的实现: HashMap和TreeMap,
  • HashMap对键进行散列, TreeMap用键的整体顺序对元素进行排序
  • 使用HashMap: 不需要按照排列顺序访问键
  • 示例代码:
package cn.kuang.java_primary.collection.pojo;

/**
 * Employee实体类
 * Created by 框 on 2018/6/19.
 */
public class Employee {
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return  name ;
    }

    public Employee() {
    }

    public Employee(String name) {
        this.name = name;
    }
}
---------------------------------------------------------
package cn.kuang.java_primary.collection;

import cn.kuang.java_primary.collection.pojo.Employee;

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

/**
 * 1. 展示映射的操作过程
 *
 * 2. 将键值对添加到映射中
 *
 * 3. 删除一个键, 对应的值也会删除
 *
 * 4. 修改和查看某个值
 *
 * Created by 框 on 2018/6/19.
 */
public class MapTest {
    public static void main(String[] args) {
        Map<String, Employee> staff = new HashMap<>();
        staff.put("114-25-5412", new Employee("Amy qw"));
        staff.put("114-25-3234", new Employee("RQs dfg"));
        staff.put("114-25-5818", new Employee("EAQ aas"));
        staff.put("114-25-9172", new Employee("Asd asd"));

        //print staff
        System.out.println(staff);

        //remove an entity by key
        staff.remove("114-25-9172");

        //replace an entity
        staff.put("114-25-3234", new Employee("Alice"));

        //get entity by key
        System.out.println(staff.get("114-25-5818"));

        //iterate through all entities
        staff.forEach(
                (k, v) -> System.out.println("key: " + k + " , value = " + v)
        );

    }
}

3.2 Map常用方法

  • V get();
  • dafault V getOrDefault(Object key, V defaultValue);
  • V put(K key, V value);
  • void putAll(Map

4. 一些其他的问题

4.1 HashMap的排序问题

已知一个HashMap<Integer, User>, 
User有name, age属性, 
编写一个方法实现HashMap的排序, 
参数为: HashMap<Integer, User>, 
返回排好序的HashMap, 
排序规则: 按照User的age进行倒序排序, 不得拆散键值对
--------------------------------------Class User-----------------------
package cn.kuang.java_primary.collection.pojo;

/**
 * HashMapSort的pojo
 * Created by 框 on 2018/6/19.
 */
public class User {
    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;
    }

    public User() {
    }

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

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

--------------------------------------Class sort-----------------------
package cn.kuang.java_primary.collection;

import cn.kuang.java_primary.collection.pojo.User;

import java.util.*;

/**
 * 已知一个HashMap<Integer, User>,
 *
 * User有name, age属性,
 *
 * 编写一个方法实现HashMap的排序,
 *
 * 参数为: HashMap<Integer, User>,
 *
 * 返回排好序的HashMap,
 *
 * 排序规则: 按照User的age进行倒序排序, 不得拆散键值对
 *
 * *************************************************************
 * 思路:
 * 使用HashMap的子类: LinkedHashMap, 他是Map结构, 也是链表结构
 *
 * 返回LInkedHashMap即可, 还满足面向接口编程
 *
 * 排序算法使用JDK中有的API
 *
 * Created by 框 on 2018/6/19.
 */
public class HashMapSort {

    public static void main(String[] args) {
        HashMap<Integer, User> hashMap = new HashMap<>();
        hashMap.put(1, new User("张三", 17));
        hashMap.put(2, new User("李四", 18));
        hashMap.put(4, new User("王二", 19));
        hashMap.put(3, new User("麻子", 20));
        System.out.println("排序前: "+hashMap);

        System.out.println("排序后: "+sortHashMapByUserAge(hashMap));

    }


    public static HashMap<Integer, User> sortHashMapByUserAge(HashMap<Integer, User> map) {
        //首先拿到Map的键值对几个
        Set<Map.Entry<Integer, User>> entrySet = map.entrySet();

        //吧set转为List集合, 方便实用sort方法
        List<Map.Entry<Integer, User>> list = new ArrayList<>(entrySet);

        //Collections的sort方法进行排序
        Collections.sort(list, new Comparator<Map.Entry<Integer, User>>() {
            @Override
            public int compare(Map.Entry<Integer, User> o1, Map.Entry<Integer, User> o2) {
                //根据User的age进行排序 倒序
                return o2.getValue().getAge() - o1.getValue().getAge();
            }
        });

        //创建一个LinkedHashMap
        LinkedHashMap<Integer, User> linkedHashMap = new LinkedHashMap<>();
        //吧list的数据存进去
        for (Map.Entry<Integer, User> entry : list){
            linkedHashMap.put(entry.getKey(), entry.getValue());
        }
        return linkedHashMap;
    }
}

4.2 集合的安全性问题

  1. Vector 和 HashTable是线程安全的, 他们的和新方法都添加了 synchronized关键字
  2. ArrayList, HashSet, HashMap是线程不安全的
  3. 可以使用以下方法来是的他们变成线程安全的
    • Collections.synchronizedCollection(c);
    • Collections.synchronizedList(list);
    • Collections.synchronizedMap(map);
    • Collections.synchronizedSet(set);

4.3 ArrayList内部实现

  • 基于Object数组实现
  • 提供了空构造器和两个带参构造器
    • 构造器1: 参数为int n, 对n进行判断, 如果n合法, 返回一个长度为 n 的ArrayList
    • 构造器2: 参数为一个Collection, 对collection进行判断, collection不为空, 则吧这个collection转为数组a, 并赋值成成员变量array, 数组长度作为成员变量size
  • 提供add方法两个:
    • 首先判断添加元素后collection容量是否还够, 不够就扩容, 够就添加
    • 未指定位置: 将新元素添加到collection的末尾
    • 指定位置: 判断位置是否合法, 合法将新元素添加到指定位置, 其后的元素位置往后挪1
  • remove:按照索引来删除:
    • 首先判断索引位置是否合法, 合法则将该索引的元素删除
    • 之后的整体往前移动一位, 将最后一个元素设置为null, 不然容易内存泄漏

4.4 并发集合和普通集合问题

  • 并发集合: 常见的:
    • ConcurrentHashMap, ConcurrentLinkedQueue, ConcurrentLinkedDeque
    • 都是位于 java.util.concurrent下,
  • Java中有普通集合, 同步集合, 并发集合
  • 普通集合效率高但是不能保证线程安全, 并发可靠
  • 同步集合仅仅添加同步锁, 严重牺牲了性能, 并发效率低
  • 并发集合既保证多线程的安全, 又提高了并发效率

4.5 List三个子类特点

  • ArrayList 底层结构是数组,底层查询快,增删慢。
  • LinkedList 底层结构是链表型的,增删快,查询慢。
  • voctor 底层结构是数组线程安全的,增删慢,查询慢。

4.6 List, Map, Set的区别

  • 结构特点:
    • List和set 都是储存单列数据的集合, Map是储存键值的双列数据集合
    • List有序可重复, Set无序不重复(位置又元素HashCode决定, 所以不能重复), Map, Key值必须唯一
  • 实现类:
    • List有三个实现类:
      • ArrayList, 数组实现, 查询更改快, 增删慢
      • LinkedList, 双向链表实现, 查询更改慢, 增删快
      • Vector, 线程安全, 效率低
    • Set实现类:
      • HashSet, 底层是HashMap实现,
      • LinkedHashSet, 继承HashSet, 基于LinkedHashMap实现
    • Map实现类:
      • HashMap, 线程不安全, 高效, 键值都支持null
      • HashTable, 线程安全, 不高效, 键值都不支持null
      • LinkedHashMap, 是HashMap的子类, 保存插入的顺序

4.7 HashMap和HashTable区别

  • HashMap, 线程不安全, 高效, 键值都支持null
  • HashTable, 线程安全, 不高效, 键值都不支持null

4.8 数组和链表的适用场景

  • ArrayList 和Vector 使用了数组的实现,可以认为ArrayList 或者Vector 封装了对内部数组的操作,比如向数组中添加,删除,插入新的元素或者数据的扩展和重定向。
  • LinkedList 使用了循环双向链表数据结构。与基于数组的ArrayList 相比,这是两种截然不同的实现技术,这也决定了它们将适用于完全不同的工作场景
  • 数组应用场景:数据比较少;经常做的运算是按序号访问数据元素;数组更容易实现,任何高级语言都支持的线性表较稳定。
  • 链表应用场景:对线性表的长度或者规模难以估计;频繁做插入删除操作;构建动态性比较强的线性表。

4.9 List a = new ArrayList(); 和 ArrayList a = new ArrayList的区别

  • List list = new ArrayList();这句创建了一个ArrayList 的对象后把上溯到了List。此时它是一个List 对象了,有些ArrayList 有但是List 没有的属性和方法,它就不能再用了。
  • 而ArrayList list=new ArrayList();创建一对象则保留了ArrayList 的所有属性。所以需要用到ArrayList 独有的方法的时候不能用前者。
package cn.kuang.java_primary.collection;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 使用队列模拟堆栈结构
 *
 * 队列a, b
 *
 * 思路:
 *
 * 1. 入栈: a, b队列为空, 将 "a, b, c, d, e" 先放入a中, a中为:  "a, b, c, d, e"
 *
 * 2. 出栈: 将a中元素倒序放入b队列中, 再将b出列
 *
 * Created by 框 on 2018/6/19.
 */
public class SimulationStack {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>(); //a 队列
        Queue<String> queue2=new LinkedList<>(); //b队列
        ArrayList<String> a=new ArrayList<>(); //arrylist集合是中间参数

        //往a队列添加元素
        queue.offer("a");
        queue.offer("b");
        queue.offer("c");
        queue.offer("d");
        queue.offer("e");
        System.out.print("进栈:");

        //a队列依次加入list集合之中
        for(String q : queue){
            a.add(q);
            System.out.print(q);
        }

        //以倒序的方法取出(a队列依次加入list集合)之中的值,加入b对列
        for(int i=a.size()-1;i>=0;i--){
            queue2.offer(a.get(i));
        }

        //打印出栈队列
        System.out.println("");
        System.out.print("出栈:");

        for (String q : queue2) {
            System.out.print(q);
        }
    }
}

4.12 遍历问题

Map遍历:
package cn.kuang.java_primary.collection;

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

/**
 * Map 的遍历方法
 *
 * 1. 获取所有key来按照key遍历
 *
 * 2. 通过Map.entrySet使用iterator遍历key和value
 *
 * 3. 通过Map.entrySet遍历key和value,推荐,尤其是容量大时
 *
 * 4. 通过Map.values()遍历所有的value,但不能遍历key
 *
 * Created by 框 on 2018/6/19.
 */
public class MapTranverse {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "tom");
        map.put(2, "noOn");
        map.put(3, "wha");
        map.put(4, "oepra");
        map.put(5, "power");
        map.put(6, "eric");
        map.put(7, "alic");
        map.put(8, "qwe");

        //1. 获取key来遍历
        for (Integer in : map.keySet()) {
            String str = map.get(in);
            System.out.println(in+ " : " +str);
        }

        System.out.println("...................................");

        //2. 通过Map.entrySet使用iterator遍历key和value
        Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
        while (it.hasNext()){
            Map.Entry<Integer, String> entry = it.next();
            System.out.println(entry.getKey()+" : "+entry.getValue());
        }

        System.out.println("...................................");

        //3. 通过Map.entrySet遍历key和value,推荐,尤其是容量大时
        for (Map.Entry<Integer, String> entry : map.entrySet()) {
            System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
        }

        System.out.println("...................................");

        //4. 通过Map.values()遍历所有的value,但不能遍历key
        for (String v : map.values()) {
            System.out.println("value= " + v);
        }

    }
}
List遍历
package cn.kuang.java_primary.collection;

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

/**
 * 主要使用for循环和迭代器
 *
 * Created by 框 on 2018/6/19.
 */
public class ListTraverse {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList();

        list.add(6);
        list.add(12);
        list.add(4);
        list.add(2);
        list.add(3);
        list.add(5);

        //1. for循环遍历
        for(Iterator iterator = list.iterator(); iterator.hasNext();){
            int i = (Integer) iterator.next();
            System.out.println(i);
        }

        System.out.println(".......................");

        //2. 迭代器
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

        System.out.println(".......................");

        //3. 增强for循环
        for (int i : list) {
            System.out.println(i);
        }


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值