zoukankan      html  css  js  c++  java
  • Java学习之路(六):集合

    集合的由来

    • 数组的长度是固定的,当添加的元素超过了数组的长度,就需要对数组重新定义
    • java内部给我们提供的集合类,能存储任意对象,长度是可以改变的。随着元素的增加而增加,随着元素的减少而减少

    数组和集合的区别

    • 数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值
    • 集合只能存储引用数据类型(对象Object),集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象  eg:int==>Integer
    •   
    • 数组长度是固定的,不能自动增长
    • 集合的长度是可变的,可以根据元素的增加而增长

    如果元素的个数是固定的,我们使用数组

    如果元素的个数不固定,我们使用集合

    集合Collection类:

    • list:有序集合,有索引。存与取的顺序一样,可以重复
      • ArrayList(数组实现)
      • LinkedList(链表实现)
      • Vector(数组实现)
    • Set:无序集合,无索引。存与取的顺序不一样,不可以重复
      • HashSet (哈希算法)
      • TreeSet(二叉树算法)

    ArrayList集合中部分数组实现的原理

      eg:有个容量为10的初始化数组,当它不够用的时候,就会自动生成一个1.5倍大的数组,将值重新赋值后,把以前的那个小的数组垃圾回收了

    Collection的几个基本方法

    • boolean add(E e)  添加一个元素
    • boolean remove(object o)   移除某一个元素
    • void clear()  清空这个集合
    • boolean contains(Object o)
    • boolean isEmpty()   判断这个集合是否为空
    • int size()   大小
    • toArray()   将集合转化为数组
    • boolean addAll(Collection c1)  将c1添加进来
    • boolean removeAll(Collection c1)  移除this中还有的c1中的所有元素
    • boolean containsAll(Collection c1)  判断this是否包含有c1中的所有元素
    • boolean retainAll(Collection c1)   求并集

    遍历一个集合,我们使用迭代器

    迭代器是用来遍历集合中的每一个元素的

    方法:hasNext()和next()

    package lesson3;
    
    //这是一个小例子
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    
    public class null03 {
    
        public static void main(String[] args) {
            Collection c1 = new ArrayList();//这不就是多态?
            c1.add("A");
            c1.add("B");
            c1.add("C");
            
            Iterator iterator = c1.iterator();
            while(iterator.hasNext()){
                Object o = iterator.next();
                System.out.println(o);
            }
            
    
        }
    
    }

     List集合

    • void add(int index,E element)
    • E remove(int index)
    • E get(int index)
    • E set(int index,E element)

    List可以通过size()和get()方法结合来遍历List集合

    package day19_null;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class null01List {
    
        public static void main(String[] args) {
            List li = new ArrayList();
            li.add("A");
            li.add("B");
            li.add("C");
            li.add("D");
            li.add(0,"E");
            for(int i=0;i<li.size();i++){
                System.out.println(li.get(i));
            }
    
        }
    
    }

    结果:

    E
    A
    B
    C
    D

    这里我们提出一道问题

    有一个集合,判断里面有没有“B”这个元素,如果有,就添加一个“b”元素。

    当我们使用iterator来遍历的时候,是不能一边遍历一遍添加值的

    package day19_null;
    //错误的写法
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class null01List {
    
        public static void main(String[] args) {
            List li = new ArrayList();
            li.add("A");
            li.add("B");
            li.add("C");
            li.add("D");
            li.add(0,"E");
            Iterator iterator = li.iterator();
            while(iterator.hasNext()){
                //System.out.println(iterator.next());
                Object o = iterator.next();
                String o_str = (String)o;
                if(o_str.equals("B")){
                    li.add("b");
                }
            }
    
        }
    
    }
    错误的写法

    所以呢,我们就要使用ListIterator这个了

    • boolean hasNext()   是否有下一个
    • boolean hasPrevious()     是否有前一个
    • Object next()   下一个元素
    • Object previous()   上一个元素

    对比一下:

    package day19_null;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.ListIterator;
    
    public class null01List {
    
        public static void main(String[] args) {
            List li = new ArrayList();
            li.add("A");
            li.add("B");
            li.add("C");
            li.add("D");
            li.add(0,"E");
            ListIterator iterator = li.listIterator();
            while(iterator.hasNext()){
                Object o = iterator.next();
                String o_str = (String)o;
                if(o_str=="B"){
                    iterator.add("b");
                }
            }
            while(iterator.hasPrevious()){
                System.out.println(iterator.previous());
            }
    
        }
    
    }

     Vector的使用

     vector在JDK1.0版本就已经有了,从v1.2开始,此类改进为可以实现List接口,使他成为Java Collections Framework成员

    Vector是同步的,也就是线程是有锁的,是安全的,当然也是效率低的

     Vector的特有功能:

    • public void addElement(E obj)
    • public E elementAt(int index)
    • public Enumeration elements()0
    package day19_null;
    
    import java.util.Enumeration;
    import java.util.Vector;
    
    public class null02_vector {
    
        public static void main(String[] args) {
            //创建一个vector对象
            Vector vec = new Vector();
            vec.addElement("A");
            vec.addElement("B");
            vec.addElement("C");
            vec.addElement("D");
            vec.addElement("E");
            System.out.println(vec.elementAt(0));
            
            Enumeration enumeration = vec.elements();
            while(enumeration.hasMoreElements()){
                System.out.println(enumeration.nextElement());
            }
        }
    
    }

     List的三个子类的特点

     ArrayList:

    • 底层数据结构是数组,查询比较块,增删比较慢
    • 线程不安全,所以块

    Vector:

    • 底层数据结构是数组,查询比较块,增删比较慢
    • 线程安全,效率较低(相对于ArrayList)

    LinkedList:

    • 底层的数据结构是链表,查询慢,增删快
    • 线程不安全,所以快

    例子:去除ArrayList中重复的对象 

     思路:创建一个新的ArrayList,然后借由新创建的ArrayList来进行判断

    package day20_nullnull;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class null01_removeSame {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            //TheUsualWayToGetRidOfWeight();
            
            TheUsualWayToGetRidOfWeightObject();
            
            
        }
    
        /**
         * 如果ArrayList中存在Object
         */
        private static void TheUsualWayToGetRidOfWeightObject() {
            List li = new ArrayList();
            li.add(new Student("null1",1));
            li.add(new Student("null2",2));
            li.add(new Student("null3",3));
            li.add(new Student("null4",4));
            li.add(new Student("null1",1));
            List li2 = new ArrayList();
            for(int i=0;i<li.size();i++){
    //            System.out.println(li.get(i));
                if(!li2.contains(li.get(i))){
                    li2.add(li.get(i));
                }
            }
            for(int i=0;i<li2.size();i++){
                System.out.println(li2.get(i));
            }
        }
    
        /**
         * 如果ArrayList中都是String
         */
        private static void TheUsualWayToGetRidOfWeight() {
            //创建一个数组
            List li = new ArrayList();
            li.add("A");
            li.add("B");
            li.add("C");
            li.add("D");
            li.add("A");
            List li2 = new ArrayList();
            for(int i=0;i<li.size();i++){
    //            System.out.println(li.get(i));
                if(!li2.contains(li.get(i))){
                    li2.add(li.get(i));
                }
            }
            for(int i=0;i<li2.size();i++){
                System.out.println(li2.get(i));
            }
        }
    
    }
    
    class Student{
        String name;
        int age;
        public Student() {
            super();
        }
        public Student(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
    
        @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + "]";
        }
    }

    注意:我们会很神奇的发现,当ArrayList中存在Object的时候,居然不行?!!

    补充: 

      我们是使用contains来进行判断新的列表是否存在的。但是在contains的内部调用的其实还是equals方法。

      在String中因为重写了equals方法,所以他是根据String的内容进行判断的

      但是,在Object判断的却是内存地址。

      所以,我们要重写class的equals方法。

    package day20_nullnull;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class null02 {
    
        public static void main(String[] args) {
            List li1 = new ArrayList();
            li1.add(new Student2("null1",1));
            li1.add(new Student2("null2",2));
            li1.add(new Student2("null3",3));
            li1.add(new Student2("null4",4));
            li1.add(new Student2("null1",1));
            List li2 = new ArrayList();
            for(int i=0;i<li1.size();i++){
                if(!li2.contains(li1.get(i))){
                    li2.add(li1.get(i));
                }
            }
            for(int i=0;i<li2.size();i++){
                System.out.println(li2.get(i));
            }
            
        }
    
    }
    
    class Student2{
        String name;
        int age;
        public Student2() {
            super();
        }
        public Student2(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        
    
        @Override
        public String toString() {
            return "Student2 [name=" + name + ", age=" + age + "]";
        }
        @Override
        public boolean equals(Object obj){
            Student2 other = (Student2) obj;
            return this.name.equals(other.name)&&this.age==other.age;
        }
        
    }

     OK,没有问题

    注意:contains内部调用的还是equals方法

    LinkedList的使用

     我们现在学了集合中list的两个ArrayList和Vector两个,这两个的底层都是Array数组

    接下来的LinkedList的底层是链表

    方法:

    • public void addFirst(E e)以及addLast(E e)
    • public E getFirst()以及getLast()
    • public E reoveFirst()以及removeLast()
    • public E get()

    使用LinkedList实现栈和队列

    • 栈:先进后出
    • 队列:先进先出
    package lesson2;
    //栈的模拟
    
    import java.util.LinkedList;
    
    public class null01 {
    
        public static void main(String[] args) {
            Stack stack = new Stack();
            
            //进栈
            stack.in("A");
            stack.in("B");
            stack.in("C");
            stack.in("D");
            stack.in("E");
            
            //出栈
            Object o = stack.out();
            System.out.println(o);
            System.out.println(stack.list);
        }
    
    }
    class Stack{
        //栈:先进后出
        LinkedList list = new LinkedList();
        
        //进栈的方法
        public void in(Object o){
            list.addFirst(o);
        }
        
        //出栈的方法
        public Object out(){
            return list.removeFirst();
        }
    }

    队列的模拟和其类似,只不过是相反而已,队列是先进先出的

    当然,其实不用写,在LinkedList的内部就已经实现了栈的一系列方法

    package lesson2;
    
    import java.util.LinkedList;
    
    public class null02 {
    
        public static void main(String[] args) {
            //创建一个栈对象
            LinkedList stack = new LinkedList();
            
            //进栈的方法
            stack.push("A");
            stack.push("B");
            stack.push("C");
            stack.push("D");
            
            //出栈的方法
            Object o1 = stack.pop();
            System.out.println(o1);
            Object o2 = stack.pop();
            System.out.println(o2);
            Object o3 = stack.pop();
            System.out.println(o3);
            Object o4 = stack.pop();
            System.out.println(o4);
            stack.pop();  //没有了还要弹,就报错了
    /**        Exception in thread "main" java.util.NoSuchElementException
                at java.util.LinkedList.removeFirst(Unknown Source)
                at java.util.LinkedList.pop(Unknown Source)
                at lesson2.null02.main(null02.java:26)*/
        }
    
    }

    泛性的概述和简单使用

    作用:把类型明确的工作推前到创建对象或者调用方法的时候

    泛型是一种参数化类型,把类型当做参数一样传递来明确集合的元素类型

    好处:

    • 提高安全性
    • 省去了强转的麻烦

    基本使用:

    • 声明集合泛型的格式:List<String> list = new ArrayList<String>();
    • <>中放的必须是引用数据类型
  • 相关阅读:
    mysql的导出与导入命令的使用
    kendo ui 左侧弹出分享框
    Pytorch离线安装方法
    Python单词接龙小程序
    Shell结束指定名称的进程
    Shell脚本sed命令修改文件的某一行
    Shell中单双引号的区别
    矩阵问题
    泛型通配符详解
    合并链表
  • 原文地址:https://www.cnblogs.com/smiling-crying/p/9339265.html
Copyright © 2011-2022 走看看