集合-上

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

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

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

原文地址:https://www.cnblogs.com/zhangxiong-tianxiadiyi/p/10798760.html