• 集合-上


    集合产生背景:传统的容器(数组)在进行增、删等破坏性操作时,需要移动元素,可能导致性能问题;同时添加、删除等算法和具体业务耦合在一起,增加了程序开发的复杂度。

    Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中

    一,Collection

    Collection是java集合框架种的顶层接口

    Collecion接口是一个容器,容器中只能存储引用数据类型,建议存同一类型的引用类型,方便后续遍历等操作。

    那简单介绍几种集合常用方法(无非也是围绕:增,删,改,查四点)

    public static void main(String[] args) {
            Collection c1=new ArrayList();
            //增  用的是 .add
            c1.add("apple");//其实这里本质上算一个多态:Object object=New String("apple");
            c1.add("banana");
            System.out.println(c1);
            //增另外一个集合  用的是   .addAll
            Collection c2=new ArrayList();
            c2.add("java");
            c2.add("c++");
            c1.addAll(c2);        
            System.out.println(c1);
                    
            //删 .clear .remove/All .retainAll
            //c1.clear(); //全部清除
            // System.out.println(c1);
             c1.remove("c++");
             System.out.println(c1);
             c1.add("c++");
             //其它两个形式和add的差不多,就不写了
                      
             //查  .contains/All isEmpty Size
             System.out.println(c1.contains("apple"));
             System.out.println(c1.containsAll(c2));
             System.out.println(c1.isEmpty());//判断c1是不是空集合
             System.out.println(c1.size());//判断c1集合里面有几个元素
             
          //改(其子类会有具体方法表示)
       }

    集合的遍历 

    Iterable可遍历的接口,几个接口继承于它,集合支持快速遍历

    for(Object item:c1){
                 System.out.println(item);
             }//这个遍历写法都是为求方便的写法

     那我们一起看下快速遍历的本质

    Collection是继承Iterable接口的。这个Iterable接口里面定义了一个方法iterator()用于获取集合的迭代器,是一个Iterator接口类型,iterator()内部返回一个实现类实现Iterator接口。这个实现类一定具有hasNext和next方法用于判断是否有下一个元素和获取下一个元素。快速遍历就是基于迭代器工作的。

    //遍历本质
             Iterator it=c1.iterator(); //迭代器
             while (it.hasNext()) {
                Object item = it.next();
                System.out.println(item);

    不过上面这种写法把迭代器写在循环外面,导致循环完了jvm也不能回收这个内存空间,所以再优化一下(把迭代器放到循环条件里面)

    //优化版本
             for(Iterator it2=c1.iterator();it2.hasNext();){
                 Object item = it2.next();
                    System.out.println(item); 
             }

    二,list接口

    list接口种的元素,有序,可重复。list接口中的元素通过索引来确定元素顺序(可初步理解为数组)

    因为list是继承自collection接口的,所以常用方法也与collection差不多

    public static void main(String[] args) {
            List list1=new ArrayList();
             
            //增:add/addAll/add(index,el)/addAll(index,collection)
             // 可以观察到与collection不同的是list可以在确定的索引处添加元素或者另一个集合
            list1.add("apple");
            list1.add("banana");
            System.out.println(list1);
            list1.add(1, "coco");//指定把元素添加在几号位上
            System.out.println(list1);
            
            //删:clear/remove/removeAll/remove(index)
            list1.remove(0);//把几号位上的元素删除
            System.out.println(list1);
            
            //改:set(index,el)
            list1.set(0, "c++");
            System.out.println(list1);
            
            //查:get(index)/indexOf/lastIndexOf()
            System.out.println(list1.get(1));
            list1.add("java");
            list1.add("js");
            System.out.println(list1);
            System.out.println(list1.indexOf("java"));
            System.out.println(list1.lastIndexOf("js"));
       }
    //其它方法:contains/containsAll/isEmpty/size 都是继承自collection接口的方法,就不多说了

    list接口遍历

    list的遍历和collection相同点都有快速遍历,迭代器遍历(继承性质)(iterator)

    不同点是list有自己的遍历方式:普通for,正(逆)向遍历(listiterator)

    public static void main(String[] args) {
            List list1=new ArrayList();    
            list1.add("apple");
            list1.add("banana");
            list1.add("coco");
            System.out.println(list1);
            //快速遍历
            for(Object item:list1){
                System.out.println(item);
            }
            
            //普通for (因为list是有序排列的,所以可以用到数组的遍历方式)
            for(int i=0;i<list1.size();i++){
                System.out.println(list1.get(i));
            }
            //迭代器(优化的写法我就不写了,把迭代器放到循环里就ok了)
            Iterator it=list1.iterator();
            while (it.hasNext()) {
                System.out.println(it.next());    
            }
            //正向遍历
            ListIterator it2=list1.listIterator();
            while (it2.hasNext()) {
                System.out.println(it2.next());
            }
            //逆序遍历(把next都改成previous就ok了)
            while (it2.hasPrevious()) {
                System.out.println(it2.previous());
            }
               //正逆序遍历之从index位开始遍历
            ListIterator it3=list1.listIterator(1);
            while (it3.hasNext()) {
                System.out.println(it3.next());
            }
       }

     ArrayList与Vector

    ArrayList 是List接口的实现类,底层数据结构是数组,实现大小可变的数组。
    ArrayList 线程不安全,jdk1.2

    ArrayList 底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,ArrayList会自动拓容,拓容原则:newCapacity = oldCapacity + oldCapacity / 2;
    如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

    ArrayList作为List接口的实现类,常用方法和遍历方法参考List接口。

    Vector 是List接口的实现类,底层数据结构也是数组,也是大小可变的数组。
    Vector是线程安全的,jdk1.0

    Vector底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,Vector会自动拓容,拓容原则:newCapacity = oldCapacity +capacityIncrement(增长因子);如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

    注意:Vector 在实现List接口的同时,同添加了自身特有的方法xxxElement,未来使用时为了程序的可拓展性,一定要按照接口来操作Vector

    LinkedList是List接口的实现类,底层数据结构是链表。(区别数组)
    LinekList常用方法和遍历方法参照List接口。
    LinkedList 线程不安全。

    public static void main(String[] args) {
            //linkedlist 除了实现list接口,也实现栈接口(用push入栈和pop出栈)
            LinkedList list=new LinkedList();
            list.push("apple");
            list.push("banana");
            list.push("coco");
            System.out.println(list);
            System.out.println(list.pop());
            System.out.println(list.pop());
            System.out.println(list.pop());
            //但是这样元素出栈完之后继续出栈会发生异常
            System.out.println(list.pop());
        }

    队列接口(Queue)

      抛出异常 返回特殊值(null)
    增加 add() offer(e)
    删除 remove() poll()
    查找 element() peek()

    区别就是抛出异常会抛出异常( java.util.NoSuchElementException)

    返回特殊值就是不会出现异常,但会返回null

    public static void main(String[] args) {
            LinkedList queue=new LinkedList();
            queue.add("apple");
            queue.add("banana");
            queue.add("coco");
            System.out.println(queue);
            System.out.println(queue.remove());
            System.out.println(queue.element());
            //返回值类型
            queue.offer("java");
            System.out.println(queue);
        }
         双向队列(Deque)接口              第一个元素(头部)                    最后一个元素(尾部)             
    抛出异常 特殊值      抛出异常 特殊值       
    增加 addFirst() offerFirst()  addLast()  offerLast()
    删除 removeFirst() pollFirst()  removeLast()  pollLast()
    检查 getFirst() peekFirst()  getLast()  peekLast()

    与队列接口不一样的就是两边都可以进行出栈和入栈(代码使用形式和上面一样就不写了)

    Iterator和lisIterator

    区别:Iterator在迭代过程中不允许向集合种添加元素(会发生ConcurrentModificationException异常)

              但是listiterator可以按任一方向便利列表

    那我这里只写listiterator

    public static void main(String[] args) {
            ArrayList list=new ArrayList();
            list.add("apple");
            list.add("banana");
            list.add("coco");
            System.out.println(list);
    //区别就在下面这句代码
            ListIterator it=list.listIterator();
            while (it.hasNext()) {
                String item=(String) it.next();
                if(item.equals("coco")){
                    it.add("java");
                }
            }
            System.out.println(list);
        }

    泛型(generic)

    将类型参数化(规定之后后面的类型只能是同一类型)

    形式:ArrayList<E>list=new ArrayList<E>();   //<E>  这个东西就是泛型

    而且泛型在编译器起作用,运行时jvm不会察觉到。(个人理解泛型就是用来规范咱们程序员代码习惯的)

    泛型类(一个类中属性数据类型不确定时,就用泛型类)

    形式:类名后面加<E>

    //定义一个泛型类
    public class Q1<E> {
        private E e;
    
        public E getE() {
            return e;
        }
    
        public void setE(E e) {
            this.e = e;
        }
    
        public Q1(E e) {
            super();
            this.e = e;
        }
    
        public Q1() {
            super();
            // TODO Auto-generated constructor stub
        }
    
    }
    public static void main(String[] args) {
            Q1<String> q1=new Q1<String>();//只准后面对象设置成字符串类型
            q1.setE("apple");
            
            Q1<Integer> q2=new Q1<Integer>();//只准后面对象设置成Integer类型
            q2.setE(1);
        }

    泛型方法(同理,方法参数类型不确定就用泛型)

    public <T> void xxx(T a) {
        System.out.println(a);
    }

    例如:

    public class Test {
        //同时声明不同类型的同一方法,之前一般是用到方法重载,但代码量大
        public void showInfo(int a) {
            System.out.println(a);
        }
    
        public void showInfo(float a) {
            System.out.println(a);
        }
    
        public void showInfo(String a) {
            System.out.println(a);
        }
    //如果用一个泛型那只需要先写个形式,后面在调方法时想写什么类型都可以
        public <T> void showInfo(T a) {
            System.out.println(a);
        }
    
    }
    public static void main(String[] args) {
            Student stu = new Student();
            stu.showInfo(1);
            stu.showInfo("apple");
            stu.showInfo(1.0f);
        }

    所以泛型就是方法重载的进化版了

  • 相关阅读:
    Git
    Qcon2016上海站PPT
    TeamCity
    在cmd界面,怎么样退出Node.js运行环境
    python 2.x与python3.x的区别
    d3.max()与d3.min()
    d3.svg.line() 曲线构造器
    d3.js 之SVG:矢量化图形绘制
    moment.js 时间格式化库
    directive
  • 原文地址:https://www.cnblogs.com/zhangxiong-tianxiadiyi/p/10798760.html
Copyright © 2020-2023  润新知