zoukankan      html  css  js  c++  java
  • 集合-上

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

    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);
        }

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

  • 相关阅读:
    Codeforces 691A Fashion in Berland
    HDU 5741 Helter Skelter
    HDU 5735 Born Slippy
    HDU 5739 Fantasia
    HDU 5738 Eureka
    HDU 5734 Acperience
    HDU 5742 It's All In The Mind
    POJ Euro Efficiency 1252
    AtCoder Beginner Contest 067 C
    AtCoder Beginner Contest 067 D
  • 原文地址:https://www.cnblogs.com/zhangxiong-tianxiadiyi/p/10798760.html
Copyright © 2011-2022 走看看