zoukankan      html  css  js  c++  java
  • java List/ArrayList 解惑

    导读:祖传挖坟派学习方法(宝儿姐友情支持)

      第一部分  List简介

      第二部分  何为ArrayList

      第三部分  代码示例

      第四部分  吹牛

    如果你急需想搞清楚一些问题可以先看这里的总结 再后续看文章

    (1)ArrayList是线程不安全的

    (2)对ArrayList里面对象的使用方法 在第三部分代码示例中 越有可能在开发中用到的方法 比如List转换MAP 都比较靠后

    第一部分  List简介

      如果你有参阅过 JDK 1.8 API中对于LIST的描述那么 你一定在文中有看到过这句话  This interface is a member of the Java Collections Framework.(此接口是Java集合框架的成员。)

    这句话为我们带来了两个提示 首先List是一个接口 其次list是collection接口的子接口,collection是集合的父类型接口 ,定义了所有集合的通用方法 。 翻阅api 我找到了关于list继承关系的结构介绍

    观察继承关系 得出如下结论:

      一 : E是泛型  意味着 list<E>该方法在调用时可以接收不同类型的参数。可以根据传递给泛型方法的参数类型 .

      二:  List的父类有两个 第一个是collection 第二个是Iterable  collection通过上面铺垫我们有所了解 。 Iterable(迭代器)我这里简短的描述下(是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节。)

      三:(所有已知的实现类)这里我们看到了 许多但是今天要讲的重点在ArrayList这个实现类上  (list是个接口 如果你要new必须要有个实现类)

    将上面一二点 汇聚成一段Java代码:

    public interface List<E> extends Collection<E>

      这段代码位于java.util.List.java类中 是包含所有List调用的方法

    目前已知情报汇总:

        (一):List是一个接口,而ArrayList是List接口的一个实现类。 

             (二):ArrayList类继承并实现了List接口。 

             (三):List接口不能被构造,也就是我们说的不能创建实例对象,但是我们可以为List接口创建一个指向自己的对象引用,而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用。 

      所以现在我应该要来弄清楚实现List接口的对象 "ArrayList"

    第二部分:何为ArrayList

      翻阅 JDK api 我找到了关于ArrayList继承关系的结构

    观察继承关系 得出如下结论:

      (一):ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
      (二):ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。

      (三):ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。

        (四):ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

    继续看下去 JDK API中开头有一段对ArrayList的描述

    翻译:

      列表接口的可调整大小的数组实现。实现所有可选的列表操作,并允许所有元素,包括空元素。除了实现列表接口之外,这个类还提供了一些方法来操作内部用于存储列表的数组的大小。(这个类大致相当于vector,只是它不同步。) 这里的不同步指的是线程不同步和Vector不同,ArrayList中的操作不是线程安全的!所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。 关于list线程不同步的测试代码 地址:https://www.cnblogs.com/WuXuanKun/p/5556999.html (感谢这位仁兄的博客)

    对上面的小总结的一个汇合结论 :

      ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它 提供了相关的添加、删除、修改、遍历等功能。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。 此外 ArrayList支持序列化,能通过序列化去传输.  ArrayList中的操作不是线程安全的

    第三部分  代码示例

    第一步在Java类里面创建List

    List<String> list = new ArrayList<>();

      我们调查一下这个new ArrayList   在java.util.ArrayList.java类中 我找到了这样一段代码,如下:

         /**
         * Constructs an empty list with an initial capacity of ten.
         */
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }

    这便是我们new的真实的ArrayList了 通过注释我们发现  我们new的 Arrayslist 其默认长度为10  

     继续调查这个 elementData  还是在java.util.ArrayList.java类中  我找到了 关于elementData  的定义

        /**
         * Shared empty array instance used for default sized empty instances. We
         * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
         * first element is added.
         */
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
        /**
         * The array buffer into which the elements of the ArrayList are stored.
         * The capacity of the ArrayList is the length of this array buffer. Any
         * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
         * will be expanded to DEFAULT_CAPACITY when the first element is added.
         */
        transient Object[] elementData; // non-private to simplify nested class access
       /**
         * Increases the capacity of this <tt>ArrayList</tt> instance, if
         * necessary, to ensure that it can hold at least the number of elements
         * specified by the minimum capacity argument.
         *
         * @param   minCapacity   the desired minimum capacity
         */
        public void ensureCapacity(int minCapacity) {
            int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // any size if not default element table
                ? 0
                // larger than default for default empty table. It's already
                // supposed to be at default size.
                : DEFAULT_CAPACITY;
    
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }

    是不是有种恍然大悟的感jio 原来ArrayList的老祖宗是一个Object的数组而观察DEFAULTCAPACITY_EMPTY_ELEMENTDATA进行的操作我们发现它为上面的Object数组 提供了进行动态操作的能力  这样从JDK源码中,我们验证了我们上面在第二部分的总结里面说到 ArrayLis其实是一个动态数组.

     总结:ArrayList底层其实就是一个Object类型的动态数组,并且通过注释也可以得知,我们在进行new操作时其初始化的长度为10。

    说了这么多我们来看看list 能使用ArrayList进行那些操作(以往博客的重头戏来了)先看看他为我们提供了那些方法

    所下示例代码均来自 博客园仁兄 “西城墨客” 所属博客 地址:https://www.cnblogs.com/epeter/p/5648026.html 

    目录

    1. list中添加,获取,删除元素;
    2. list中是否包含某个元素;
    3. list中根据索引将元素数值改变(替换);
    4. list中查看(判断)元素的索引;
    5. 根据元素索引位置进行的判断;
    6. 利用list中索引位置重新生成一个新的list(截取集合);
    7. 对比两个list中的所有元素;
    8. 判断list是否为空;
    9. 返回Iterator集合对象;
    10. 将集合转换为字符串;
    11. 将集合转换为数组;
    12. 集合类型转换;
    13. 去重复;
    14. List转换MAP
    15. List分组
    16. List 遍历

    1.list中添加,获取,删除元素;

      添加方法是:.add(e);  获取方法是:.get(index);  删除方法是:.remove(index); 按照索引删除;  .remove(Object o); 按照元素内容删除;

    List<String> person=new ArrayList<>();
                person.add("jackie");   //索引为0  //.add(e)
                person.add("peter");    //索引为1
                person.add("annie");    //索引为2
                person.add("martin");   //索引为3
                person.add("marry");    //索引为4
                 
                person.remove(3);   //.remove(index)
                person.remove("marry");     //.remove(Object o)
                 
                String per="";
                per=person.get(1);
                System.out.println(per);    ////.get(index)
                 
                for (int i = 0; i < person.size(); i++) {
                    System.out.println(person.get(i));  //.get(index)
                }
    View Code

    2.list中是否包含某个元素;

    方法:.contains(Object o); 返回true或者false

    List<String> fruits=new ArrayList<>();
                fruits.add("苹果");
                fruits.add("香蕉");
                fruits.add("桃子");
                //for循环遍历list
                for (int i = 0; i < fruits.size(); i++) {
                    System.out.println(fruits.get(i));
                }
                String appleString="苹果";
                //true or false
                System.out.println("fruits中是否包含苹果:"+fruits.contains(appleString));
                 
                if (fruits.contains(appleString)) {
                    System.out.println("我喜欢吃苹果");
                }else {
                    System.out.println("我不开心");
                }
    View Code

    3.list中根据索引将元素数值改变(替换);

    注意 .set(index, element); 和 .add(index, element); 的不同;

    String a="白龙马", b="沙和尚", c="八戒", d="唐僧", e="悟空";
                List<String> people=new ArrayList<>();
                people.add(a);
                people.add(b);
                people.add(c);
                people.set(0, d);   //.set(index, element);     //将d唐僧放到list中索引为0的位置,替换a白龙马
                people.add(1, e);   //.add(index, element);     //将e悟空放到list中索引为1的位置,原来位置的b沙和尚后移一位
                 
                //增强for循环遍历list
                for(String str:people){
                    System.out.println(str);
                }
    View Code

    4.list中查看(判断)元素的索引; 

    注意:.indexOf(); 和  lastIndexOf()的不同;

    List<String> names=new ArrayList<>();
                names.add("刘备");    //索引为0
                names.add("关羽");    //索引为1
                names.add("张飞");    //索引为2
                names.add("刘备");    //索引为3
                names.add("张飞");    //索引为4
                System.out.println(names.indexOf("刘备"));
                System.out.println(names.lastIndexOf("刘备"));
                System.out.println(names.indexOf("张飞"));
                System.out.println(names.lastIndexOf("张飞"));
    View Code

    5.根据元素索引位置进行的判断;

    if (names.indexOf("刘备")==0) {
        System.out.println("刘备在这里");
    }else if (names.lastIndexOf("刘备")==3) {
        System.out.println("刘备在那里");
    }else {
        System.out.println("刘备到底在哪里?");
    }
    View Code

    6.利用list中索引位置重新生成一个新的list(截取集合);

    方法: .subList(fromIndex, toIndex);  .size() ; 该方法得到list中的元素数的和

    List<String> phone=new ArrayList<>();
                phone.add("三星");    //索引为0
                phone.add("苹果");    //索引为1
                phone.add("锤子");    //索引为2
                phone.add("华为");    //索引为3
                phone.add("小米");    //索引为4
                //原list进行遍历
                for(String pho:phone){
                    System.out.println(pho);
                }
                //生成新list
                phone=phone.subList(1, 4);  //.subList(fromIndex, toIndex)      //利用索引1-4的对象重新生成一个list,但是不包含索引为4的元素,4-1=3
                for (int i = 0; i < phone.size(); i++) { // phone.size() 该方法得到list中的元素数的和
                    System.out.println("新的list包含的元素是"+phone.get(i));
                }
    View Code

    7.对比两个list中的所有元素;

    //两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象

    //1.<br>if (person.equals(fruits)) {
        System.out.println("两个list中的所有元素相同");
    }else {
        System.out.println("两个list中的所有元素不一样");
    }
    //2.       
    if (person.hashCode()==fruits.hashCode()) {
        System.out.println("我们相同");
    }else {
        System.out.println("我们不一样");
    }
    View Code

    8.判断list是否为空;

    //空则返回true,非空则返回false

    if (person.isEmpty()) {
        System.out.println("空的");
    }else {
        System.out.println("不是空的");
    }
    View Code

    9.返回Iterator集合对象;

    System.out.println("返回Iterator集合对象:"+person.iterator());

    1+0.将集合转换为字符串;

    String liString="";
    liString=person.toString();
    System.out.println("将集合转换为字符串:"+liString);
    View Code

    11.将集合转换为数组;

        
    System.out.println("将集合转换为数组:"+person.toArray());
    View Code

    12.集合类型转换;

    //1.默认类型
    List<Object> listsStrings=new ArrayList<>();
      for (int i = 0; i < person.size(); i++) {
        listsStrings.add(person.get(i));
    }
    //2.指定类型
    List<StringBuffer> lst=new ArrayList<>();
      for(String string:person){
      lst.add(StringBuffer(string));
    }
    View Code

    13.去重复;

    List<String> lst1=new ArrayList<>();
                lst1.add("aa");
                lst1.add("dd");
                lst1.add("ss");
                lst1.add("aa");
                lst1.add("ss");
     
                       //方法 1.
                for (int i = 0; i <lst1.size()-1; i++) {
                    for (int j = lst1.size()-1; j >i; j--) {
                        if (lst1.get(j).equals(lst1.get(i))) {
                            lst1.remove(j);
                        }
                    }
                }
                System.out.println(lst1);
                 
                       //方法 2.
                List<String> lst2=new ArrayList<>();
                for (String s:lst1) {
                    if (Collections.frequency(lst2, s)<1) {
                        lst2.add(s);
                    }
                }
                System.out.println(lst2);
    View Code

    完整代码:

    package MyTest01;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class ListTest01 {
     
        public static void main(String[] args) {
             
                //list中添加,获取,删除元素
                List<String> person=new ArrayList<>();
                person.add("jackie");   //索引为0  //.add(e)
                person.add("peter");    //索引为1
                person.add("annie");    //索引为2
                person.add("martin");   //索引为3
                person.add("marry");    //索引为4
                 
                person.remove(3);   //.remove(index)
                person.remove("marry");     //.remove(Object o)
                 
                String per="";
                per=person.get(1);
                System.out.println(per);    ////.get(index)
                 
                for (int i = 0; i < person.size(); i++) {
                    System.out.println(person.get(i));  //.get(index)
                }
                 
                 
             
                //list总是否包含某个元素
                List<String> fruits=new ArrayList<>();
                fruits.add("苹果");
                fruits.add("香蕉");
                fruits.add("桃子");
                //for循环遍历list
                for (int i = 0; i < fruits.size(); i++) {
                    System.out.println(fruits.get(i));
                }
                String appleString="苹果";
                //true or false
                System.out.println("fruits中是否包含苹果:"+fruits.contains(appleString));
                 
                if (fruits.contains(appleString)) {
                    System.out.println("我喜欢吃苹果");
                }else {
                    System.out.println("我不开心");
                }
                 
                //list中根据索引将元素数值改变(替换)
                String a="白龙马", b="沙和尚", c="八戒", d="唐僧", e="悟空";
                List<String> people=new ArrayList<>();
                people.add(a);
                people.add(b);
                people.add(c);
                people.set(0, d);   //.set(index, element)      //将d唐僧放到list中索引为0的位置,替换a白龙马
                people.add(1, e);   //.add(index, element);     //将e悟空放到list中索引为1的位置,原来位置的b沙和尚后移一位
                 
                //增强for循环遍历list
                for(String str:people){
                    System.out.println(str);
                }
                 
                //list中查看(判断)元素的索引
                List<String> names=new ArrayList<>();
                names.add("刘备");    //索引为0
                names.add("关羽");    //索引为1
                names.add("张飞");    //索引为2
                names.add("刘备");    //索引为3
                names.add("张飞");    //索引为4
                System.out.println(names.indexOf("刘备"));
                System.out.println(names.lastIndexOf("刘备"));
                System.out.println(names.indexOf("张飞"));
                System.out.println(names.lastIndexOf("张飞"));
                 
                //根据元素索引位置进行的判断
                if (names.indexOf("刘备")==0) {
                    System.out.println("刘备在这里");
                }else if (names.lastIndexOf("刘备")==3) {
                    System.out.println("刘备在那里");
                }else {
                    System.out.println("刘备到底在哪里?");
                }
                 
                //利用list中索引位置重新生成一个新的list(截取集合)
                List<String> phone=new ArrayList<>();
                phone.add("三星");    //索引为0
                phone.add("苹果");    //索引为1
                phone.add("锤子");    //索引为2
                phone.add("华为");    //索引为3
                phone.add("小米");    //索引为4
                //原list进行遍历
                for(String pho:phone){
                    System.out.println(pho);
                }
                //生成新list
                phone=phone.subList(1, 4);  //.subList(fromIndex, toIndex)      //利用索引1-4的对象重新生成一个list,但是不包含索引为4的元素,4-1=3
                for (int i = 0; i < phone.size(); i++) { // phone.size() 该方法得到list中的元素数的和
                    System.out.println("新的list包含的元素是"+phone.get(i));
                }
                 
                //对比两个list中的所有元素
                //两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象
                if (person.equals(fruits)) {
                    System.out.println("两个list中的所有元素相同");
                }else {
                    System.out.println("两个list中的所有元素不一样");
                }
                 
                if (person.hashCode()==fruits.hashCode()) {
                    System.out.println("我们相同");
                }else {
                    System.out.println("我们不一样");
                }
                 
                 
                //判断list是否为空
                //空则返回true,非空则返回false
                if (person.isEmpty()) {
                    System.out.println("空的");
                }else {
                    System.out.println("不是空的");
                }
                 
                //返回Iterator集合对象
                System.out.println("返回Iterator集合对象:"+person.iterator());
                 
                //将集合转换为字符串
                String liString="";
                liString=person.toString();
                System.out.println("将集合转换为字符串:"+liString);
                 
                //将集合转换为数组,默认类型
                System.out.println("将集合转换为数组:"+person.toArray());
                 
                ////将集合转换为指定类型(友好的处理)
                //1.默认类型
                List<Object> listsStrings=new ArrayList<>();
                for (int i = 0; i < person.size(); i++) {
                    listsStrings.add(person.get(i));
                }
                //2.指定类型
                List<StringBuffer> lst=new ArrayList<>();
                for(String string:person){
                    lst.add(StringBuffer(string));
                }
                 
                 
                 
                 
        }
     
        private static StringBuffer StringBuffer(String string) {
            return null;
        }
     
     
        }
    View Code

    14:List转换Map (示例代码来自:https://www.cnblogs.com/yangweiqiang/p/6934671.html) 感谢这位小火纸

    随便来个Java类 添加一个List 测试数据 

    List<Apple> appleList = new ArrayList<>();//存放apple对象集合
    
    Apple apple1 =  new Apple(1,"苹果1",new BigDecimal("3.25"),10);
    Apple apple12 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);
    Apple apple2 =  new Apple(2,"香蕉",new BigDecimal("2.89"),30);
    Apple apple3 =  new Apple(3,"荔枝",new BigDecimal("9.99"),40);
    
    appleList.add(apple1);
    appleList.add(apple12);
    appleList.add(apple2);
    appleList.add(apple3);

    id为key,apple对象为value,可以这么做:ps 此方法只适用于JDK1.8+

    /**
     * List -> Map
     * 需要注意的是:
     * toMap 如果集合对象有重复的key,会报错Duplicate key ....
     *  apple1,apple12的id都为1。
     *  可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
     */
    Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));

    15:List分组

    List里面的对象元素,以某个属性来分组,例如,以id分组,将id相同的放在一起:

    //List 以ID分组 Map<Integer,List<Apple>>
    Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));
    
    System.err.println("groupBy:"+groupBy);
    {1=[Apple{id=1, name='苹果1', money=3.25, num=10}, Apple{id=1, name='苹果2', money=1.35, num=20}], 2=[Apple{id=2, name='香蕉', money=2.89, num=30}], 3=[Apple{id=3, name='荔枝', money=9.99, num=40}]}

    16:list遍历

    List<String> list = new ArrayList<String>();
    list.add("aaa");
    list.add("bbb");
    list.add("ccc");
    方法一:
    超级for循环遍历
    for(String attribute : list) {
      System.out.println(attribute);
    }
    方法二:
    对于ArrayList来说速度比较快, 用for循环, 以size为条件遍历:
    for(int i = 0 ; i < list.size() ; i++) {
      system.out.println(list.get(i));
    }
    方法三:
    集合类的通用遍历方式, 从很早的版本就有, 用迭代器迭代
    Iterator it = list.iterator();
    while(it.hasNext()) {
      System.ou.println(it.next);
    }
    View Code
  • 相关阅读:
    Cron表达式,springboot定时任务
    go 语言中windows Linux 交叉编译
    SSM框架处理跨域问题
    golang gin解决跨域访问
    关于Integer类的值使用==比较
    IoC注解
    spring基础知识
    SQL SERVER大话存储结构(3)_数据行的行结构
    SQL SERVER
    MySQL-记一次备份失败的排查过程
  • 原文地址:https://www.cnblogs.com/hwcs/p/10518572.html
Copyright © 2011-2022 走看看