Java 集合

154 阅读5分钟

这是我参与 8 月更文挑战的第 28 天,活动详情查看:8 月更文挑战

ArrayList

与数组的区别

  • 数组局限性 : 当要存放多个对象时,如果对象数量不确定,就难以新建数组,因为数组长度一旦固定就不再可变;为解决这一局限性,引入容器 ArrayList,其容量会随对象增加而不断自动改变,不用担心边界问题;
import java.util.ArrayList;

public class Demo{
    public static void main(String[] args){
        int[] array = new int[10];
        arr[0] = 10;
        arr[20] = 3; // 越界
        
        // 不用担心边界问题
        ArrayList<Integer> list = new ArrayList<>();
        list.add(24);
        list.add(54);
        
    }
}

常用方法

方法功能
add(Object obj)/add(int index, Object obj)末尾增加对象/指定索引位置加入对象
contains(Object obj)判断某对象是否存在容器中
get(int index)获取指定位置的对象
indexOf(Object obj)获取对象所处位置
remove(Object obj)/remove(int index)删除指定对象/指定位置的对象
set(int index, Object obj)替换指定位置元素
size()获取容器大小
toArray()转换为数组
addAll(ArrayList arrayList)将另一个容器中所有对象加入进来
clear()清空

泛型 Generic

不指定泛型的容器,可以存放任意类型的元素,取出数据时需要转型;指定了泛型的容器,只能存放指定类型的元素及其子类;

遍历

  • for
import java.util.ArrayList;
import java.util.Iterator;
import java.utils.List;

public class Demo{
	public static void main(String[] args){
        List<Integer> list = new ArrayList<>();
        
        for(int i = 0; i < 5; i++){
            list.add(i + 1);
        }
        
        for(int j = 0; j < list.size(); j++){
            System.out.println(list.get(j));
        }
    }
}
  • for:
import java.util.ArrayList;
import java.util.Iterator;
import java.utils.List;

public class Demo{
	public static void main(String[] args){
        List<Integer> list = new ArrayList<>();
        
        for(int i = 0; i < 5; i++){
            list.add(i + 1);
        }
        
        for(Integer num : list){
            System.out.println(num);
        }
    }
}
  • iterator
import java.util.ArrayList;
import java.util.Iterator;
import java.utils.List;

public class Demo{
	public static void main(String[] args){
        List<Integer> list = new ArrayList<>();
        
        for(int i = 0; i < 5; i++){
            list.add(i + 1);
        }
        
        // while 循环
        Iterator<Integer> it = list.iterator();
        while(it.hasNext()){
            Integer num = it.next();
            System.out.println(num);
        }
        
        // for 循环
        for(Iterator<Integer> iterator = list.iterator();iterator.hasNexxt();){
            Integer numInt = (Integer) iterator.next();
            System.out.println(numInt);
        }
    }
}

LinkedList

  • 序列分为 先进先出 FIFO先进后出 FILOFIFO 又叫 队列 QueueFILO 又叫 栈 Stack
  • 双向链表 Deque :方便在头尾增删数据;
import java.util.LinkedList;

public class Demo{
    public static void main(String[] args){
        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        
        // 在头尾增加数据
        linkedList.addFirst(9);
        linkedList.addFirst(34);
        linkedList.addLast(3);
        
        // 在头尾删除数据
        System.out.println(linkedList.removeFirst());
        System.out.println(linkedList.removeLast());
        
        // 查看头尾数据
        System.out.println(linkedList.getFirst());
        System.out.println(linkedList.getLast());
    }
}
  • 队列 Queue

队列是 FIFO,有如下常用方法;

方法功能
offer(Object obj)在队尾添加元素
poll()取出队首元素
peek()查看队首元素
import java.util.LinkedList;
import java.util.Queue;

public class Demo{
    public static void main(String[] args){
        Queue<Integer> queue = new LinkedList<Integer>();
        
        // 队尾添加元素
        queue.offer(34);
        queue.offer(43);
        
        // 查看队首元素
        System.out.println(queue.peek());
        
        // 取出队首元素
        System.out.println(queue.poll());
    }
}

二叉树

  • 定义 :由各种 节点 组成,每个节点可以有 左右子节点,每个节点均有一个
publc class Node{
    // 左右节点 + 值
    public Node leftNode;
    public Node rightNode;
    public Object value;
}
  • 排序
public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;

    // 值
    public Object value;

    // 插入 数据
    public void add(Object v) {
        // 如果当前节点没有值,就把数据放在当前节点上
        if (null == value)
            value = v;

            // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
        else {
            // 新增的值,比当前值小或者相同

            if ((Integer) v -((Integer)value) <= 0) {
                if (null == leftNode)
                    leftNode = new Node();
                leftNode.add(v);
            }
            // 新增的值,比当前值大
            else {
                if (null == rightNode)
                    rightNode = new Node();
                rightNode.add(v);
            }

        }

    }

    public static void main(String[] args) {

        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };

        Node roots = new Node();
        for (int number : randoms) {
            roots.add(number);
        }
    }
}

  • 遍历

遍历分为 左序、中序、右序

  1. 左序:中间的数遍历后放在左边;
  2. 中序:中间的数遍历后放在中间;
  3. 右序:中间的数遍历后放在右边;
/**
 * Created with IntelliJ IDEA.
 * Version : 1.0
 * Author  : cunyu
 * Email   : cunyu1024@foxmail.com
 * Website : https://cunyu1943.github.io
 * 公众号   : 村雨遥
 * Date    : 2020/5/15 下午12:40
 * Project : mavenDemo
 * Package : PACKAGE_NAME
 * Class   : Node
 * Desc    : 中序遍历
 */

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

public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;

    // 值
    public Object value;


    /**
     * 插入数据
     *
     * @param v 待插入的数据
     */
    public void add(Object v) {
        // 如果当前节点没有值,就把数据放在当前节点上
        if (null == value)
            value = v;

            // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
        else {
            // 新增的值,比当前值小或者相同

            if ((Integer) v - ((Integer) value) <= 0) {
                if (null == leftNode)
                    leftNode = new Node();
                leftNode.add(v);
            }
            // 新增的值,比当前值大
            else {
                if (null == rightNode)
                    rightNode = new Node();
                rightNode.add(v);
            }

        }

    }

    /**
     * 中序遍历
     * @return 中序遍历后的 List
     */
    public List<Object> middleIterator() {
        List<Object> values = new ArrayList<>();

        // 左节点的遍历结果
        if (null != leftNode)
            values.addAll(leftNode.middleIterator());

        // 当前节点
        values.add(value);

        // 右节点的遍历结果
        if (null != rightNode)

            values.addAll(rightNode.middleIterator());

        return values;
    }

    /**
     * 左序遍历
     *
     * @return 左序遍历后的 List
     */
    public List<Object> forwardIterator() {
        List<Object> values = new ArrayList<>();

        values.add(value);

        if (null != leftNode) {
            values.add(leftNode.forwardIterator());
        }

        if (null != rightNode) {
            values.add(rightNode.forwardIterator());
        }

        return values;
    }

    /**
     * 右序遍历
     * @return 右序遍历后的数组
     */
    public List<Object> behindIterator() {
        List<Object> values = new ArrayList<>();
        if (null != leftNode) {
            values.add(leftNode.forwardIterator());
        }

        if (null != rightNode) {
            values.add(rightNode.forwardIterator());
        }
        values.add(value);

        return values;
    }

    public static void main(String[] args) {

        int[] randoms = new int[]{67, 7, 73};

        Node roots = new Node();
        for (int number : randoms) {
            roots.add(number);
        }

        System.out.println(roots.middleIterator());
        System.out.println(roots.forwardIterator());
        System.out.println(roots.behindIterator());
    }
}

HashMap

HashMap 是通过 键值对 的方式存储数据,其中 键是唯一的,值是可以重复的,所以当以同样的 key 将不同 value 加到 HashMap 将导致原来的元素被覆盖

/**
 * Created with IntelliJ IDEA.
 * Version : 1.0
 * Author  : cunyu
 * Email   : cunyu1024@foxmail.com
 * Website : https://cunyu1943.github.io
 * 公众号   : 村雨遥
 * Date    : 2020/5/15 下午1:05
 * Project : mavenDemo
 * Package : PACKAGE_NAME
 * Class   : Demo
 * Desc    :
 */

import java.util.HashMap;

public class Demo {
    public static void main(String[] args) {
        HashMap<String, String> dict = new HashMap<>();
        
        dict.put("坦克", "牛头");
        dict.put("射手", "伽罗");
        dict.put("射手", "后裔");
        
        System.out.println(dict.get("射手"));
    }
}

HashSet

  • HashSet元素不能重复,而且是无序的
/**
 * Created with IntelliJ IDEA.
 * Version : 1.0
 * Author  : cunyu
 * Email   : cunyu1024@foxmail.com
 * Website : https://cunyu1943.github.io
 * 公众号   : 村雨遥
 * Date    : 2020/5/15 下午1:05
 * Project : mavenDemo
 * Package : PACKAGE_NAME
 * Class   : Demo
 * Desc    :
 */


import java.util.HashSet;

public class Demo {
    public static void main(String[] args) {
        HashSet<String> names = new HashSet<>();

        names.add("后羿");
        names.add("伽罗");

        System.out.println(names);
        
        // 插入相同数据,容器中只保留一个
        names.add("后羿");

        System.out.println(names);
    }
}

  • 遍历 : HashSet 无序,所以无法通过 get() 获取指定位置元素,只能通过 迭代器或增强型 for 循环 来遍历;
/**
 * Created with IntelliJ IDEA.
 * Version : 1.0
 * Author  : cunyu
 * Email   : cunyu1024@foxmail.com
 * Website : https://cunyu1943.github.io
 * 公众号   : 村雨遥
 * Date    : 2020/5/15 下午1:05
 * Project : mavenDemo
 * Package : PACKAGE_NAME
 * Class   : Demo
 * Desc    :
 */


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

public class Demo {
    public static void main(String[] args) {
        HashSet<String> names = new HashSet<>();

        names.add("后羿");
        names.add("伽罗");

        System.out.println(names);

        // 增强 for 循环遍历
        for (String name : names) {
            System.out.println(name);
        }

        // 迭代器遍历
        for (Iterator<String> iterator = names.iterator();iterator.hasNext();){
            String name = (String) iterator.next();
            System.out.println(name);
        }
    }
}

HashMap 和 HashSet 的区别

HashSet 没有独立的实现,而是在其中封装了一个 MapHashSet 是作为 Mapkey 而存在的,而 value 是一个名为 PRESENT 的静态对象,属于类属性,有且只有一个;

private static final Object PRESENT = new Object();
/**
* HashSet 源码
*/
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
 
public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    //HashSet里封装了一个HashMap
    private  HashMap<E,Object> map;
 
    private static final Object PRESENT = new Object();
 
    //HashSet的构造方法初始化这个HashMap
    public HashSet() {
        map = new HashMap<E,Object>();
    }
 
    //向HashSet中增加元素,其实就是把该元素作为key,增加到Map中
    //value是PRESENT,静态,final的对象,所有的HashSet都使用这么同一个对象
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
 
    //HashSet的size就是map的size
    public int size() {
        return map.size();
    }
 
    //清空Set就是清空Map
    public void clear() {
        map.clear();
    }
     
    //迭代Set,就是把Map的键拿出来迭代
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }
 
}

Collection vs Collections

Collection

CollectionSet、List、Queue、Deque 的接口;

graph TB
A[Collection] --- B[Set]
A[Collection] --- C[List]
A[Collection] --- D[Queue]
A[Collection] --- E[Deque]
B[Set] --- F[SortedSet]
C[List] --- G[ArrayList]
C[List] --- H[LinkedList]
C[List] --- I[Vector]

Collections

Collections 是一个类,容器的工具类,如同 Arrays 数组的工具类。主要有如下常用方法:

方法功能
reverse(List<?> list)反转
shuffle(List<?> list)打乱
sort(List<?> list)从小到大排序
swap(List<?> list, int i, int j)交换 ij 两个位置的元素
rotate(List<?> list, int distance)向右滚动 distance 个单位
synchronizedList(List<?> list)将非线程安全的 List 转换为线程安全的 List
/**
 * Created with IntelliJ IDEA.
 * Version : 1.0
 * Author  : cunyu
 * Email   : cunyu1024@foxmail.com
 * Website : https://cunyu1943.github.io
 * 公众号   : 村雨遥
 * Date    : 2020/5/15 下午1:05
 * Project : mavenDemo
 * Package : PACKAGE_NAME
 * Class   : Demo
 * Desc    :
 */


import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            list.add(i + 1);
        }

        System.out.println(list);

        // 翻转
        Collections.reverse(list);
        System.out.println(list);

        // 打乱
        Collections.shuffle(list);
        System.out.println(list);

        // 排序
        Collections.sort(list);
        System.out.println(list);

        // 交换
        Collections.swap(list, 3, 4);
        System.out.println(list);

        // 向右滚动
        Collections.rotate(list, 3);
        System.out.println(list);

        List<Integer> synchronizedNumList = (List<Integer>) Collections.synchronizedList(list);
        System.out.println(synchronizedNumList);
    }
}

关系与区别

ArrayList vs HashSet

  • ArrayList :有顺序,数据能够重复;

  • HashSet :无顺序(既不是插入顺序,也不是 hashcode 的顺序),数据不能重复;

  • 判断是否重复的标准

    • hashcode 不同 :则认为是不同数据;
    • hashcode 相同比较 equals ,若 equals 相同,则是相同数据,否则不是;

ArrayList vs LinkedList

  • ArrayList插入、删除数据较慢,属于顺序结构,因此定位快
  • LinkedList插入、删除数据较快,属于链表结构,因此定位慢

HashMap vs HashTable

两者都是实现了 Map 接口,都以 键值对 的方法保存数据;

  • HashMap能够存放 null,不是线程安全的类
  • HashTable不能存放 null,是线程安全的类

几种 Set

  • HashSet无序
  • LinkedHashSet按照插入顺序
  • TreeSet从小到大排序

其他

比较器

Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
    
class Hero{
    public String name;
    public float hp;
  
    public int damage;
  
    public Hero() {
  
    }
  
    public Hero(String name) {
 
        this.name = name;
    }
  
    public String toString() {
        return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
    }
 
    public Hero(String name, int hp, int damage) {
        this.name = name;
        this.hp = hp;
        this.damage = damage;
    }
}
     
public class TestCollection {
    public static void main(String[] args) {
        Random r =new Random();
        List<Hero> heros = new ArrayList<Hero>();
            
        for (int i = 0; i < 10; i++) {
            //通过随机值实例化hero的hp和damage
            heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100)));
        }
        System.out.println("初始化后的集合:");
        System.out.println(heros);
            
        //直接调用sort会出现编译错误,因为Hero有各种属性
        //到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
        //Collections.sort(heros);
            
        //引入Comparator,指定比较的算法
        Comparator<Hero> c = new Comparator<Hero>() {
            @Override
            public int compare(Hero h1, Hero h2) {
                //按照hp进行排序
                if(h1.hp>=h2.hp)
                    return 1;  //正数表示h1比h2要大
                else
                    return -1;
            }
        };
        Collections.sort(heros,c);
        System.out.println("按照血量排序后的集合:");
        System.out.println(heros);
    }
}

Comparable

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

class Hero implements Comparable<Hero>{
    public String name;
    public float hp;
       
    public int damage;
       
    public Hero(){
          
    }
      
    public Hero(String name) {
        this.name =name;
  
    }
      
    //初始化name,hp,damage的构造方法
    public Hero(String name,float hp, int damage) {
        this.name =name;
        this.hp = hp;
        this.damage = damage;
    }
  
    @Override
    public int compareTo(Hero anotherHero) {
        if(damage<anotherHero.damage)
            return 1; 
        else
            return -1;
    }
  
    @Override
    public String toString() {
        return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
    }
      
}
 
public class Demo {
    public static void main(String[] args) {
        Random r =new Random();
        List<Hero> heros = new ArrayList<Hero>();
          
        for (int i = 0; i < 10; i++) {
            //通过随机值实例化hero的hp和damage
            heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100)));
        }
          
        System.out.println("初始化后的集合");
        System.out.println(heros);
          
        //Hero类实现了接口Comparable,即自带比较信息。
        //Collections直接进行排序,无需额外的Comparator
        Collections.sort(heros);
        System.out.println("按照伤害高低排序后的集合");
        System.out.println(heros);
          
    }
}

总结

以上就是今天关于 Java 集合的相关知识总结了,如果你觉得我的文章对你有所帮助,那就点赞关注我吧!