List的使用

作者~小明学编程 

文章专栏Java数据结构

格言目之所及皆为回忆,心之所想皆为过往
在这里插入图片描述

目录

常见方法

难点分析

ArrayList(顺序表)

构造方法

ArrayList的大小以及增容问题

打印顺序表

参考源码实现顺序表(2.0版本)

List实战练习(扑克牌发牌器)


常见方法

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex)截取部分 list
    public static void main(String[] args) {
        ArrayList<String> lis = new ArrayList<>();
        lis.add("hello");
        lis.add("world");
        lis.add("!");
        lis.add("hello");
        System.out.println(lis);//[hello, world, !, hello]
        lis.add(2,"q");
        System.out.println(lis);//[hello, world, q, !, hello]
        lis.remove(1);
        System.out.println(lis);//[hello, q, !, hello]
        lis.remove("hello");
        System.out.println(lis);//[q, !, hello]
}

难点分析

ArrayList(顺序表)

构造方法

方法解释
ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量

如上表所示我们ArrayList()的构造方法一共有三种,第一种就是我们的无参构造,这种构造方法不用传参数直接new一个顺序表出来。

        ArrayList<String> lis = new ArrayList<>();

第二种就是有参数的构造方法我们传一个已有的顺序表。

    public static void main(String[] args) {
        ArrayList<String> lis = new ArrayList<>();
        lis.add("q");
        lis.add("w");
        ArrayList<String> lis1 = new ArrayList<>(lis);
        System.out.println(lis1);//[q, w]
    }

第三种则是传参传一个initialCapacity也就是给我们的顺序表一个初始容量。

        ArrayList<String> lis = new ArrayList<>(10);

ArrayList的大小以及增容问题

        ArrayList<String> lis = new ArrayList<>();
        System.out.println(lis.size());//0

我们可以看到当我们无参构造的时候我们顺序表的大小居然是0,那么顺表的大小是0的话就肯定不能去放元素进去,所以这中间肯定会进行一个扩容的。我们通过查看源码并分析得出了这样的一个结论。

如果ArrayList调用不带参数的构造方法,那么顺序表的大小初始为0,当第一次add的时候,整个顺序表的大小将会变成10,之后每次放满在不超过最大增容限制的时候就会进行1.5倍的扩容,如果给定容量的大小了,那么初始值就是给定的大小(不超过最大限制),之后每次满了之后还是进行1.5倍的扩容。

打印顺序表

1.直接打印

System.out.println(lis);//toString方法打印

2.fori遍历

        for (int i=0;i < lis.size();i++) {
            System.out.println(lis.get(i));
        }

通过我们的get()方法依次获取指定下标的元素进行打印。

3.forreach遍历

        for (String ret: lis) {
            System.out.println(ret);
        }

4.迭代器打印

        //迭代器打印
        Iterator<String> it = lis.iterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
        //迭代器list相关打印
        ListIterator it2 = lis.listIterator();
        while(it.hasNext()) {
            System.out.println(it2.next());
        }
public interface ListIterator<E> extends Iterator<E>

这是我们点开的源码我们可以看到 ListIterator<E> 继承了 Iterator<E>,所以ListIterator中将会有一些 Iterator中所没有的一些方法。

注意事项:

在我们使用Iterator的时候remove()之前必须得有next(),不能让迭代器在同一个位置remove()两次,否则的话将会抛出以下的异常。

        Iterator<String> it = lis.iterator();
        while(it.hasNext()) {
            it.remove();
            System.out.println(it.next());
        }
Exception in thread "main" java.lang.IllegalStateException

所以我们想要删除集合中某一个元素的时候我们需要先next()迭代出当前的元素,然后再对其进行一个remove()。

正确的写法如下:

        Iterator<String> it = lis.iterator();
        while(it.hasNext()) {
            String ret = it.next();
            if (ret.equals("hello")) {
                it.remove();
            } else {
                System.out.println(ret);
            }
        }

———————————————————————————————————————————

利用迭代器在读取的时候插入数据:

        ListIterator<String> it2 = lis.listIterator();
        System.out.println("============");
        while(it2.hasNext()) {
            String ret = it2.next();
            if (ret.equals("hello")) {
                it2.add("hahaha");
            } else {
                System.out.println(ret);
            }
        }
        System.out.println("===============^");
        System.out.println(lis);//[q, !, hello, hahaha]

值得注意的是我们的迭代器在读取的时候是可以it2.add,但是不能lis.add(),因为我们的ArrayList是单线程的属于线程不安全的,否则的话将会抛出异常。

参考源码实现顺序表(2.0版本)

class MyArrayList<E> {
    private Object[] elementData;//数组
    private int useSize;//有效的数据个数
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认的空数组
    //不带参数的构造方法
    public MyArrayList () {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    //带参数的构造方法
    public MyArrayList (int capacity) {
        if (capacity>0) {
            this.elementData = new Object[capacity];
        } else if (capacity==0) {
            this.elementData = new Object[0];
        } else {
            throw new IllegalArgumentException("初始容量小于0了");
        }
    }
    public boolean add (E e) {
        //确定一个真正的容量,判断一波是否需要扩容
        ensureCapacityInternal(useSize + 1);
        //现在可以放心的向里面放元素了
        elementData[useSize++] = e;
        return true;
    }
    public void add(int index,E e) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(useSize+1);
        copy(index,e);//拷贝数组
        useSize++;
    }
    public int size() {
        return useSize;
    }
    private void copy(int index,E e) {
        for(int i=useSize-1;i>=index;i--) {
            elementData[i+1] = elementData[i];
        }
        elementData[index] = e;
    }

    private void rangeCheckForAdd(int index) {
        if (index > size() || index < 0)
            throw new IndexOutOfBoundsException("index的位置不合法!");
    }
    private void ensureCapacityInternal(int minCapacity) {
        //计算得出分析之后的容量
        int capacity = calculateCapacity(elementData,minCapacity);
        ensureExplicitCapacity(capacity);

    }
    private void ensureExplicitCapacity(int minCapacity) {
        // 若分析之后的容量大于当前的容量则开始扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    private static int MAX_ARRAY_SIZE = Integer.MAX_VALUE-8;
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //确定新的容量的大小
        int newCapacity = oldCapacity + (oldCapacity >> 1);//扩大1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果没有分配过大小
            return Math.max(10,minCapacity);//返回一个10
        }
        return minCapacity;
    }

}

List实战练习(扑克牌发牌器)

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

//扑克牌类
class Card {
    private int rank;//数字
    private String suit;//花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    public String toString() {
        return "[ "+this.suit+" "+this.rank+" ]";
    }
}
public class Test {
    private static final String[] suits = {"♥","♠","♣","♦"};//花色数组
    //买牌
    public static List<Card> buyCard() {
        //new一个顺序表用于存放我们的Card,这边给一个初始值因为我们已只牌的数量
        List<Card> lis = new ArrayList<>(52);
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <= 13; j++) {
                String suit = suits[i];
                int rank = j;
                Card card = new Card(rank,suit);
                lis.add(card);
            }
        }
        return lis;
    }
    //交换两个位置的牌
    private static void swap(List<Card> cards,int i,int j) {
        Card card = cards.get(i);
        cards.set(i,cards.get(j));
        cards.set(j,card);
    }
    //定义一个洗牌的方法
    public static void shuffle(List<Card> cards) {
        int size = cards.size();
        for (int i = size-1;i>0;i--) {
            Random random = new Random();
            int rand = random.nextInt(i);
            swap(cards,i,rand);
        }
    }
    public static void main(String[] args) {
        System.out.println("买牌中");
        List<Card> cards = buyCard();
        System.out.println("洗牌中");
        shuffle(cards);
        System.out.println("开始发牌");
        ArrayList<List<Card>> hand = new ArrayList<>();
        List<Card> hand1 = new ArrayList<>();
        List<Card> hand2 = new ArrayList<>();
        List<Card> hand3 = new ArrayList<>();
        hand.add(hand1);
        hand.add(hand2);;
        hand.add(hand3);
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                hand.get(j).add(cards.remove(0));
            }
        }
        System.out.println("第1个人的牌"+hand1);
        System.out.println("第2个人的牌"+hand2);
        System.out.println("第3个人的牌"+hand3);
        System.out.println("剩余的牌"+cards);

    }
    public static void main1(String[] args) {
        Card card = new Card(7,"♥");
        System.out.println(card.toString());
    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值