zoukankan      html  css  js  c++  java
  • 5.1 java类集(java学习笔记)Collection、List接口及ArrayList、LinkedList类。

    一、类集

    类集就是一组动态的对象数组,说类集可能不好理解,类集又称容器,容器顾名思义就是放东西的地方。

    类集就是为了让我们更加简洁,方便的存放、修改、使用数据的。

    二、Collection接口

    我们看下文档中的描述,Collection这个接口主要是代表容器的规范,主要用于实现其他具体功能的子接口。

    Collection更像是一个抽象出来的规则,它代表了一种标准和规范,具体的容器的实现是依靠子接口去实现的。

    Collection只是定义了一种标准,其他的子接口必须按照这个标准来,也可是说是其他子类必须完成这个标准所规定的内容。

    三、List接口、ArrayList类

    List是Collection的一个子接口,在Collection原有的基础上进行了一定扩充,List中存放的内容是允许重复的。

    我们来看文档对它的描述:

    An ordered collection (also known as a sequence). 

    有序集合(也称为序列)。更直白一点就是一个放数据的容器,而且是有序的。

    ArrayList是一个类,它继承自abstractArrayList,而abstractArrayList继承了Collection接口。

    这关系有点乱,我们来看下图。

    ArrayList看名字就知道和数组有关,新建一个ArrayList对象里面存储方式是数组。

    这就是ArrayList中存储数据的数组。

    我们先介绍一个方法,就是向容器中添加数据。

    add(E e);

    我们简单的看下源码,将传递进来的数据e添加数组elementData中,然后size++,就是一个普通的往数组后面添加元素的操作。

    这里E是泛型,由使用时决定。

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 
     4 public class test {
     5     //ArrayList Collection
     6     public static void main(String[] args) {
     7         List<Integer> list = new ArrayList<>();
     8         list.add(1);
     9         list.add(2);
    10         list.add(3);
    11         System.out.println(list);
    12     }
    13 }
    运行结果:
    [1, 2, 3]

    代码中为什么要像List<Integer> l = new ArrayList<>();这样写?

    而不直接ArrayList<Integer> i = new ArrayList<>()写?

    可能有的人会有疑问,我一开始也有疑问。

    关于这个问题可以参考:

     https://www.cnblogs.com/huang-changfan/p/9613971.html

    四、ArrayList类中常用方法

    1、E get(int index); 

    返回指定数组指定下标的数据。

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 
     4 public class test {
     5     //ArrayList Collection
     6     public static void main(String[] args) {
     7         List<Integer> list = new ArrayList<>();
     8         list.add(1);
     9         list.add(2);
    10         list.add(3);
    11         System.out.println(list.get(1));
    12     }
    13 }
    运行结果:
    2

     

    我们看下源码中get方法的实现也很简单,首先是一个下标检查,判断下标是否合法(大于等于0小于size),然后直接返回数组中指定下标的元素。

    2、addAll(Collection<? extends E> c)

    添加一组数据,传递进去的泛型参数设置了上限。

    import java.util.ArrayList;
    import java.util.List;
    
    public class test {
        //ArrayList Collection
        public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            List<Integer> list2 = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list2.add(4);
            list2.add(5);
            list2.add(6);
            list2.addAll(list); //将list里面的全部数据添加到list2中
            System.out.println(list2);
        }
    }
    运行结果:
    [4, 5, 6, 1, 2, 3]

    list中存有1,2,3.list2中存有4,5,6.然后将list中的内容添加到list2中,

    list2中就有了4,5,6,1,2,3。

    3、indexOf(Object obj)

    返回指定内容的下标。

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 
     4 public class test {
     5     //ArrayList Collection
     6     public static void main(String[] args) {
     7         List<Integer> list = new ArrayList<>();
     8         list.add(1);
     9         list.add(2);
    10         list.add(3);    
    11         System.out.println(list.indexOf(3));
    12     }
    13 }
    运行结果:
    2

     

    我们来看indexOf的源码,首选项判断是否为为空,是的话对数组遍历,如果有元素为空的话直接返回该元素下标。

    反之,也是遍历,调用Object类中equals方法进行比较,注意Object中的equals方法是比较值用的是==。

    4.remove(int index)

    删除指定位置的元素。

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 
     4 public class test {
     5     //ArrayList Collection
     6     public static void main(String[] args) {
     7         List<Integer> list = new ArrayList<>();
     8         list.add(1);
     9         list.add(2);
    10         list.add(3);
    11         list.remove(2);
    12         
    13         System.out.println(list);
    14         System.out.println(list.size());
    15     }
    16 }
    运行结果:
    [1, 2] 2

    我们来看下源码是怎么操作的。

    我们看实现功能的核心部分,

    System.arraycopy(elementData, index+1, elementData, index,numMoved);

    这是一个数组拷贝函数,例如我这里index为1,那么从2开始将后面的所有数据前移一位,最后一位加个null。

    这样index = 1的那一项就被覆盖了,达到了删除效果。

    其余remove函数也大同小异。

    五、Vector类

    Vector是一个比较古老的类,考虑到很多人员已经习惯了Vector,所以后来将其实现了List接口被保留了下来。

    因为Vector也实现了List接口,所以用法与之前的无太大差异。

    六、LinkedList类

    LinkList同样是实现了List接口的一个子类。

    它的存储方式是链表,相关的一些操作方法由于是实现List接口的,所以功能上与ArrayList大概是相同的。只是由于数据的存储方式不同

    所以具体功能的实现与ArrayList有区别。

    下面举个例子:

    add(E e);

     1 import java.util.ArrayList;
     2 import java.util.LinkedList;
     3 import java.util.List;
     4 
     5 public class test {
     6     //ArrayList Collection
     7     public static void main(String[] args) {
     8         List<Integer> list = new LinkedList<>();
     9         list.add(1);
    10         list.add(2);
    11         list.add(3);
    12         
    13         System.out.println(list);
    14         System.out.println(list.size());
    15     }
    16 }
     运行结果:
     [1, 2, 3]
     3

     可以看出实现的功能是相同的。

    但我们来看下源码:

     可以看到,这里添加元素并不是想ArrayList那样添加,通过链表的连接添加数据。

    我可以尝试下,自己实现一个简易的LinkedList 

    下面写的简易版的LinkedList实现了添加,正序遍历和反序遍历,remove,get。

      1 public class test {
      2     //ArrayList Collection
      3     public static void main(String[] args) {
      4         MyLinkedList<Integer> list = new MyLinkedList<>();
      5         list.add(1);
      6         list.add(2);
      7         list.add(3);
      8         list.fOutLinked();
      9     //    System.out.println(list.size);
     10         //list.get(1);
     11         list.remove(1);
     12         list.fOutLinked();
     13         
     14     }
     15 }
     16 
     17 class MyLinkedList<E>{  //自己实现的简易LinkedList类
     18     int size = 0;
     19     private Node<E> first;//创建用于存放头结点结点。
     20     private Node<E> last; //创建用于存放末尾结点的结点。
     21     public void add(E e){  //添加方法
     22         if(first == null){  //如果没有头结点,即什么结点都没有创建,是第一次创建结点时
     23             Node<E> n = new Node<E>();//首先创建一个结点
     24             n.setDate(e);              //将该节点中的数据区方法传递进来的数据
     25             n.setFirst(null);          //并将头结点的头部放入null
     26             n.setLast(null);           //同时将头结点的尾部放入null
     27             first = n;                 //然后将n给头结点和尾结点
     28             last = n;                  //因为这时双向链表,所以在只有一个结点的时候,
     29             size++;                    //该节点即是头结点,也是尾结点。
     30         }else{
     31             Node<E> n = new Node<E>();//如果已经有了结点。
     32             n.setFirst(last);  //则将新建结点的头部存放前一结点的信息
     33             last.setLast(n);   //然后将前一个结点的尾部设置为新建结点。
     34             n.setDate(e);      //然后将新建结点中的数据区放入传递进来的数据   
     35             n.setLast(null);   //然后将新建结点的尾部放null
     36             last = n;          //然后将新建结点作为尾结点
     37             size++;
     38         }
     39     }
     40     public void fOutLinked(){//正序输出
     41         Node<E> f = new Node<E>();
     42         f= first;          //新建一个结点,并将头结点给它。
     43         System.out.println(f.getDate()); //打印该结点的数据。
     44         while(f.getLast()!= null){       //如果该节点的尾部不为null则:
     45             f = f.getLast();             //将f结点之后的一个结点赋给f,此时f存放的是f之后的结点。
     46             System.out.println(f.getDate());//打印出该节点的数据
     47         }
     48     }
     49     public void lOutLinked(){  //逆序与正序思想相同
     50         Node<E> l = new Node<E>();
     51         l= last;
     52         System.out.println(l.getDate());
     53         while(l.getFirst()!= null){
     54             l = l.getFirst();
     55             System.out.println(l.getDate());
     56         }
     57     }
     58     
     59     public void get(int index){//获取指定位的数据。
     60         int temp = 0;
     61         Node<E> f = new Node<E>();
     62         f= first;
     63         if(index == 0){//如果index ==0 ,直接打印头结点的数据。
     64             System.out.println(f.getDate());
     65         }else{
     66             while(f.getLast()!= null){  //反之,判断下该节点的尾部是否为空
     67                 f = f.getLast();       //不为null则将f结点存放后一结点信息。
     68                 temp++;                //同时temp++,每次后移一个结点就加一
     69                 if(temp == index){     //如果temp == index,则代表找到了指定位的结点
     70                     System.out.println(f.getDate());//打印
     71                 }
     72             }
     73         }
     74         
     75     }
     76     
     77     public void remove(int index){//移处指定位的结点
     78         Node<E> l = new Node<>(); //首先创建两个结点,用于存放头结点,和尾结点。
     79         Node<E> f = new Node<>();
     80         int count = 0;  //判断当前结点是否为指定结点,每次后移一位会加一
     81         f = first;
     82         l = last;
     83         if(index == 0){//如果移除的结点为头结点,则将头结点后面结点的头部设置为null
     84             first.getLast().setFirst(null);//first.getLast()代表头结点后的结点,
     85         }else                              //然后后面的结点设置本身的头部为null
     86             if(index == size - 1){         //如果移除的结点为尾结点
     87                 last.getFirst().setLast(null);//则将尾结点之前结点的尾部设置为null。
     88             }else{
     89                 while(count<size-1){//如果要移除的结点既不是头结点,也不是尾结点。
     90                     f = f.getLast();//那么从头结点开始遍历,
     91                     count++;//每后移一个结点,count++
     92                     if(count == index){ //如果找到了指定结点
     93                         f.getFirst().setLast(f.getLast()); //将指定结点的前一个结点的尾部,设置为指定结点的后一个结点。
     94                         f.getLast().setFirst(f.getFirst());//将指定结点的后一个结点的头部,设置为指定结点的前一个结点。
     95                         f.setFirst(null);//将指定结点的头部和尾部设置为null
     96                         f.setLast(null);
     97                     }
     98                 }
     99             
    100             }    
    101     }
    102 }
    103 
    104 class Node<E>{                 //结点
    105     private Node<E> first; //存放前一结点的结点
    106     private E date;        //存放信息
    107     private Node<E> last;   //存放后一个结点的结点
    108     public Node<E> getFirst() {//后面就是一些set,get方法
    109         return first;
    110     }
    111     public void setFirst(Node<E> first) {
    112         this.first = first;
    113     }
    114     public E getDate() {
    115         return date;
    116     }
    117     public void setDate(E date) {
    118         this.date = date;
    119     }
    120     public Node<E> getLast() {
    121         return last;
    122     }
    123     public void setLast(Node<E> last) {
    124         this.last = last;
    125     }
    126 }
  • 相关阅读:
    The Water Problem HDU-5443
    约瑟夫环1
    迪杰斯特拉算法1 HDU-1874
    [20200729NOIP提高组模拟T2]学数数——坎坷
    [20200728NOIP提高组模拟T4]有趣的有趣的家庭菜园——自闭了
    [20200728NOIP提高组模拟T1]Copy
    [20200728NOIP提高组模拟T2]愉快的logo设计
    [20200727NOIP提高组模拟T3]计算几何
    [20200727NOIP提高组模拟T2]走路
    [CQOI2015]任务查询系统
  • 原文地址:https://www.cnblogs.com/huang-changfan/p/9583784.html
Copyright © 2011-2022 走看看