行业资讯
【南京java开发】java集合框架是什么?(一)
2019-10-17

随着正厚软件java班的开授,我们的课程分享也开始增加了java开发端的内容,如果你觉得有用,喜欢请记得关注,转发喔!

 


 

 

·  正  ·  文  ·  来  ·  啦  ·

 

  Java集合就是一个容器。面向对象语言对事物的体现都是以对象的形式存在,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。如果往集合里存放基本数据类型,在存取过程中会有个自动装箱和拆箱。

 

    因为容器中数据结构不同,容器有很多种。不断地将共性功能向上抽取,形成了集合体系,称之为集合框架。

 

 

 

    集合框架的顶层就称之为Collection接口。所有的集合类都位于java.util包下,查阅API可以得到如下体系结构。在使用一个体系时,原则:参阅顶层内容。建立底层对象。

 

 


 

    集合和数组的区别:

 

  1:数组是固定长度的;集合可变长度的。

 

  2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。

 

  3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

 

Collection<E>接口

 

    Collection:单列集合

 

         |--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引,允许重复元素。

 

         |--Set:无序(存入和取出顺序有可能不一致),不允许重复元素,必须保证元素的唯一性。

 

    java.util.Collection接口中的共性方法有:

 

    1.添加:

       boolean add(Object obj):一次添加一个。

       boolean addAll(Collection c):将指定容器中的所有元素添加。

 

    2.删除:

       void clear():将集合中的元素全删除,清空集合。

       boolean remove(Object o):删除集合中指定的对象。注意:删除成功,集合的长度会改变。

       boolean removeAll(Collection c):删除部分元素。部分元素和传入Collection一致。

 

    3.取交集:

       boolean retainAll(Collection c):对当前集合中保留和指定集合中的相同的元素。

       如果两个集合元素相同,返回false;如果retainAll修改了当前集合,返回true

 

    4.获取长度:

       int size():集合中有几个元素。

 

    5.判断:

       boolean isEmpty():集合中是否有元素。 

       boolean contains(Object o):集合中是否包含指定元素。

       boolean containsAll(Collection c)集合中是否包含指定的多个元素。

 

    6.将集合转成数组。

       toArray()

       toArray([])

 

    下面的代码就是演示Collection中的基本功能。

 

package ustc.maxiaolun.collection.demo;

 

import java.util.ArrayList;

import java.util.Collection;

 

public class CollectionDemo {

public static void main(String[] args) {

Collection coll = new ArrayList();

methodDemo(coll);

System.out.println("------------------");

methodAllDemo();

}

/*

 * 演示Collection中的基本功能。

 */

public static void methodDemo(Collection coll){

 

//1.添加元素。

coll.add("abc1");

coll.add("abc2");

coll.add("abc3");

 

//2.删除

coll.remove("abc2");//移除和添加元素 --> 会改变集合的长度 --> 集合里面实际上存的是对象们的引用

 

//3.清除。

coll.clear();

 

//4.判断包含。

System.out.println("contains: "+coll.contains("abc1"));//底层实现判断用的是equals()

 

System.out.println(coll);

}

 

/*

 * 演示带All的方法。

 */

public static void methodAllDemo(){

 

//1.创建两个容器。

Collection c1 = new ArrayList();

Collection c2 = new ArrayList();

 

//2.添加元素。

c1.add("abc1");

c1.add("abc2");

c1.add("abc3");

c1.add("abc4");

 

c2.add("abc2");

c2.add("abc3");

c2.add("abc5");

 

//往c1中添加c2

c1.addAll(c2);

 

//判断c1中是否包含c2中的所有元素。

boolean b = c1.containsAll(c2);

System.out.println("b = "+b);

 

//从c1中删除c2。将c1中和c2相同的元素从c1中删除。

c1.removeAll(c2);

 

//将c1中和c2不同的元素从c1中删除。保留c1中和c2相同的元素。

c1.retainAll(c2);

System.out.println(c1);

}

}

 

    7.取出集合元素。

        Iterator iterator():获取集合中元素上迭代功能的迭代器对象。

Iterator<E>接口

 

    java.util.Iterator接口是一个对 collection 进行迭代的迭代器,作用是取出集合中的元素。

 

    Iterator iterator():获取集合中元素上迭代功能的迭代器对象。

 

    迭代:取出元素的一种方式。有没有啊?有!取一个。还有没有啊?有!取一个。还有没有啊?没有。算了。

 

    迭代器:具备着迭代功能的对象。迭代器对象不需要new。直接通过 iterator()方法获取即可。

 

    迭代器是取出Collection集合中元素的公共方法。

 

 

 

    每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式。为了便于操作所有的容器,取出元素,将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口。

 

    也就说,只要通过该接口就可以取出Collection集合中的元素,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性。

 

    Iterator it = coll.iterator();//获取容器中的迭代器对象,至于这个对象是是什么不重要。这对象肯定符合一个规则Iterator接口。

 

package ustc.maxiaolun.collection.demo;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.Iterator;

 

public class IteratorDemo {

 

public static void main(String[] args) {

 

//1.创建集合。

Collection coll = new ArrayList();

 

coll.add("abc1");

coll.add("abc2");

coll.add("abc3");

 

//方式一:获取该容器的迭代器。

Iterator it = coll.iterator();

while(it.hasNext()){

System.out.println(it.next());

}

 

//方式二:直接for+alt+/,选择第三个。

for (Iterator it = coll.iterator(); it.hasNext();) {

System.out.println(it.next());

}

 

System.out.println(it.next());//abc1

System.out.println(it.next());//abc2

System.out.println(it.next());//abc3

System.out.println(it.next());//java.util.NoSuchElementException

}

}

     为了降低容器的数据结构和取出容器元素的方法之间的耦合性,把访问、取出容器元素的容器的内部类进行共性抽取,即各种容器的相应内部类都实现了Iterator接口,实现了hasNext()next()remove()方法。例如如下截取自ArrayList类的iterator()方法的底层实现代码:

public Iterator<E> iterator() {

        return new Itr();//取出ArrayList容器中元素的迭代器功能,返回的是一个Itr()迭代器对象,也就是实现Iterator接口的内部类对象。

    }

 

    /**

     * An optimized version of AbstractList.Itr

     */

    private class Itr implements Iterator<E> {//-->ArrayList容器的内部类,实现了Iterator迭代接口(迭代器),里面有hasNext()next()remove()方法。

        int cursor;       // index of next element to return

        int lastRet = -1; // index of last element returned; -1 if no such

        int expectedModCount = modCount;

 

        public boolean hasNext() {

            return cursor != size;

        }

 

@SuppressWarnings("unchecked")

        public E next() {

            checkForComodification();

            int i = cursor;

            if (i >= size)

                throw new NoSuchElementException();

            Object[] elementData = ArrayList.this.elementData;

            if (i >= elementData.length)

                throw new ConcurrentModificationException();

            cursor = i + 1;

            return (E) elementData[lastRet = i];

        }

 

        public void remove() {

            if (lastRet < 0)

                throw new IllegalStateException();

            checkForComodification();

 

            try {

                ArrayList.this.remove(lastRet);

                cursor = lastRet;

                lastRet = -1;

                expectedModCount = modCount;

            } catch (IndexOutOfBoundsException ex) {

                throw new ConcurrentModificationException();

            }

        }

 

        @Override

        @SuppressWarnings("unchecked")

        public void forEachRemaining(Consumer<? super E> consumer) {

            Objects.requireNonNull(consumer);

            final int size = ArrayList.this.size;

            int i = cursor;

            if (i >= size) {

                return;

            }

            final Object[] elementData = ArrayList.this.elementData;

            if (i >= elementData.length) {

                throw new ConcurrentModificationException();

            }

            while (i != size && modCount == expectedModCount) {

                consumer.accept((E) elementData[i++]);

            }

            // update once at end of iteration to reduce heap write traffic

            cursor = i;

            lastRet = i - 1;

            checkForComodification();

        }

 

        final void checkForComodification() {

            if (modCount != expectedModCount)

                throw new ConcurrentModificationException();

        }

    }

List<E>接口

   List本身是Collection接口的子接口,具备了Collection的所有方法。List集合的具体子类:子类之所以区分是因为内部的数据结构(存储数据的方式)不同。

 

   List:有序(元素存入集合顺序和取出一致),元素都有索引,允许重复元素-->自定义元素类型都要复写equals方法。

        |--Vector:底层的数据结构是数组。数组是可变长度的。线程同步的。增删和查询都巨慢!

        |--ArrayList:底层的也是数组结构,也是长度可变的。线程不同步的,替代了Vector。增删速度不快。查询速度很快。(因为在内存中是连续空间)

        |--LinkedList:底层的数据结构是链表,线程不同步的。增删速度很快。查询速度较慢。(因为在内存中需要一个个查询、判断地址来寻找下一元素)

 

    可变长度数组的原理:

    不断new新数组并将原数组元素复制到新数组。即当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。

 

    ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。

 

    Vector:是按照原数组的100%延长。

 

    首先学习List体系特有的共性方法,查阅方法发现List的特有方法都有索引(角标),这是该集合最大的特点。也就是说,List的特有方法都是围绕索引(角标)定义的。

 

    List集合支持对元素的增、删、改、查。

 

    1.添加()

        add(index, element):在指定的索引位插入元素。

        addAll(index, collection):在指定的索引位插入一堆元素。

 

    2.删除()

        remove(index):删除指定索引位的元素。返回被删的元素。

 

    3.获取()

        element get(index):通过索引获取指定元素。

        int indexOf(element):获取指定元素第一次出现的索引位,如果该元素不存在返回—1;所以,通过—1,可以判断一个元素是否存在。

        int lastIndexOf(element) :反向索引指定元素的位置。

        List subList(start,end) :获取子列表。

 

    4.修改()

        element set(index, newElement):对指定索引位进行元素的修改。

 

    下面的代码演示了List的特有方法:

 

package ustc.maxiaolun.list.demo;

 

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

 

public class ListDemo {

 

public static void main(String[] args) {

List list = new ArrayList();

methodDemo(list);

}

/*

 * 演示List特有的方法。

 */

public static void methodDemo(List list){

//1.常规添加元素。

list.add("abc1");

list.add("abc2");

list.add("abc3");

 

//2.插入元素。

list.add(1,"hehe");

 

//3.删除。

list.remove(1);

list.remove(1);

 

//4.获取。

System.out.println(list.get(3));// java.lang.IndexOutOfBoundsException

System.out.println(list.get(1));

System.out.println(list.indexOf("abc3"));

 

//5.修改。

list.set(1,"keke");

 

System.out.println(list);

 

//6.取出集合中所有的元素。

for (Iterator it = list.iterator(); it.hasNext();) {

System.out.println("iterator: "+it.next());

}

 

//7.List集合特有的取出方式。遍历。

for (int i = 0; i < list.size(); i++) {

System.out.println("get: "+list.get(i));

}

}

}

    5.获取所有元素:

    ListIterator listIterator():list集合特有的迭代器。

    在进行list列表元素迭代的时候,如果想要在迭代过程中,想要对元素进行操作的时候,比如满足条件添加新元素。会发生ConcurrentModificationException并发修改异常。

 

    导致的原因是:集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。

 

    如何解决呢?既然是在迭代中对元素进行操作,找迭代器的方法最为合适。可是Iterator中只有hasNext,next,remove方法。通过查阅的它的子接口,ListIterator,发现该列表迭代器接口具备了对元素的增、删、改、查的动作。

 

    ListIterator是List集合特有的迭代器。

 

    ListIterator it = list.listIterator; //取代Iterator it = list.iterator;

 

 

 

package ustc.maxiaolun.list.demo;

 

import java.util.ArrayList;

import java.util.List;

import java.util.ListIterator;

 

public class ListIteratorDemo {

 

public static void main(String[] args) {

 

List list = new ArrayList();

 

list.add("abc1");

list.add("abc2");

list.add("abc3");

list.add("abc4");

 

//需求:在遍历的过程中,如果遍历到abc2,添加一个元素haha

for (Iterator it = list.iterator(); it.hasNext();) {

Object obj = it.next();//java.util.ConcurrentModificationException

if(obj.equals("abc2")){

list.add("haha");

}

}

//上述代码出现的问题:

//迭代器it在操作容器元素,迭代过程中使用了集合对象list同时对元素进行操作。

//产生迭代结果的不确定性,引发了并发修改异常。

//解决思想:在迭代过程中,想要执行一些操作,使用迭代器的方法就可以了。

 

//使用List集合特有的迭代器:ListIterator,通过List集合的方法listIterator()获取该列表迭代器对象。

//ListIterator可以实现在迭代过程中的增删改查,还可以逆向遍历。(底层使用了List集合的角标)

//总结:在迭代过程中想要对列表List元素进行操作的时候,就要使用列表迭代器ListIterator.

 

for (ListIterator it = list.listIterator(); it.hasNext();) {

Object obj = it.next();

if(obj.equals("abc2")){

it.add("haha");

}

}

System.out.println(list);//[abc1, abc2, haha, abc3, abc4]

}

}

ArrayList<E>类

    接下来先讨论List接口的第一个重要子类:java.util.ArrayList<E>类,我这里先抛开泛型不说,本篇后面有专门阐述。但要注意,由于还没有使用泛型,利用Iteratornext()方法取出的元素必须向下转型,才可使用子类特有方法。针对ArrayList类,我们最需要注意的是,ArrayListcontains方法底层使用的equals方法判别的,所以自定义元素类型中必须复写Objectequals方法。

 

    针对这个问题,我们来讲几个小练习。

 

    练习1: ArrayList中存储自定义对象。Person(name, age)

 

    思路:

    1.描述Person

    2.定义容器对象。

    3.将多个Person对象,存储到集合中。

    4.取出Person对象。-->注意自定义对象复写toString方法,直接打印p才有意义。

 

package ustc.maxiaolun.list.test;

 

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

 

import ustc.maxiaolun.domian.Person;

 

public class ArrayListTest {

 

public static void main(String[] args) {

 

//1.创建ArrayList集合对象。

List list = new ArrayList();

 

//2.添加Person类型的对象。

Person p1 = new Person("lisi1", 21);

Person p2 = new Person("lisi2", 22);

 

list.add(p1);//add(Object obj)

list.add(p2);

list.add(new Person("lisi3", 23));

 

//3.取出元素。

for (Iterator it = list.iterator(); it.hasNext();) {

//it.next():取出的元素都是Object类型的。需要用到具体对象内容时,需要向下转型。

Person p = (Person)it.next();

System.out.println(p.getName()+":"+p.getAge());//如果不向下转型,Object类对象没有getNamegetAge方法。

}

}

}

    练习2:定义功能,去除ArrayList集合中的重复元素。

    思路:

    1.最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素。

    2.对原有容器进行元素的获取,并到临时容器中去判断是否存在。容器本身就有这功能,判断元素是否存在。

        -->contains()底层原理就是使用的equals(),而且这里用的是String类复写的的equals

    3.存在就不存储,不存在就存储。

    4.遍历完原容器后,临时容器中存储的就是唯一性的元素。

package ustc.maxiaolun.list.test;

 

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.util.ListIterator;

 

public class ArrayListTest2 {

 

public static void main(String[] args) {

/*

 * 练习2:定义功能,去除ArrayList集合中的重复元素。

 */

List list = new ArrayList();

list.add("abc1");

list.add("abc4");

list.add("abc2");

list.add("abc1");

list.add("abc4");

list.add("abc4");

list.add("abc2");

list.add("abc1");

list.add("abc4");

list.add("abc2");

 

System.out.println(list);//[abc1, abc4, abc2, abc1, abc4, abc4, abc2, abc1, abc4, abc2]

singleElement2(list);

System.out.println(list);//[abc1, abc4, abc2]

}

 

/*

 * 取出重复元素方式一。

 * 定义功能,取出重复元素。因为List带有角标,比较容易进行for循环。

 */

public static void singleElement(List list){

for (int x = 0; x < list.size()-1; x++){

Object obj = list.get(x);

for(int y = x+1; y < list.size(); y++){

if (obj.equals(list.get(y))){

list.remove(y--);//记住:removeadd等方法,会改变原数组长度!注意角标变化。

}

}

}

}

 

/*

 * 取出重复元素方式二。

 * 思路:

 * 1.最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素。

 * 2.对原有容器进行元素的获取,并到临时容器中去判断是否存在。容器本身就有这功能,判断元素是否存在。

 * 3.存在就不存储,不存在就存储。

 * 4.遍历完原容器后,临时容器中存储的就是唯一性的元素。

 */

public static void singleElement2(List list){

//1.定义一个临时容器

List temp = new ArrayList();

 

//2.遍历原容器

for (Iterator it = list.iterator(); it.hasNext();) {

Object obj = (Object) it.next();

 

//3.在临时容器中判断遍历到的元素是否存在

if(!temp.contains(obj))//contains()底层原理就是使用的equals(),而且这里用的是String类复写的equals

//如果不存在,就存储到临时容器中

temp.add(obj);

}

//将原容器清空

list.clear();

//将临时容器中的元素都存储到原容器中

list.addAll(temp);

}

}

    练习3ArrayList取出重复的自定义元素。

    记住:往集合里面存储自定义元素,该元素所属类一定要覆盖equalstoString方法!

 

package ustc.maxiaolun.domian;

 

public class Person{

private String name;

private int age;

public Person() {

super();

}

public Person(String name, int age) {

super();

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

/*

 * 建立Person类自己的判断对象是否相同的依据,必须要覆盖Object类中的equals方法。

 */

public boolean equals(Object obj) {

//为了提高效率,如果比较的对象是同一个,直接返回true即可。

if(this == obj)

return true;

 

if(!(obj instanceof Person))

throw new ClassCastException("类型错误");

Person p = (Person)obj;

 

return this.name.equals(p.name) && this.age==p.age;

}

/*@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

Person other = (Person) obj;

if (age != other.age)

return false;

if (name == null) {

if (other.name != null)

return false;

} else if (!name.equals(other.name))

return false;

return true;

}*/

}

     contains()方法底层调用的是容器中元素对象的equals()方法!这里如果Person类自身不定义equals方法,就使用Objectequals方法,比较的就仅仅是地址了。

 

package ustc.maxiaolun.list.test;

 

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

 

import ustc.maxiaolun.domian.Person;

 

public class ArrayListTest3 {

 

public static void main(String[] args) {

/*

 * 练习3ArrayList取出重复的自定义元素。

 *

 * 记住:往集合里面存储自定义元素,该元素所属类一定要覆盖equalstoString方法!

 */

List list = new ArrayList();

Person p = new Person("li",19);

list.add(p);

list.add(p);//存储了一个地址相同的对象。在equals方法中直接先this==obj即可。

list.add(new Person("li",20));

list.add(new Person("li",23));

list.add(new Person("li",26));

list.add(new Person("li",23));

list.add(new Person("li",26));

list.add(new Person("li",20));

 

System.out.println(list);

singleElement(list);

System.out.println(list);

}

public static void singleElement(List list){

List temp = new ArrayList();

for (Iterator it = list.iterator(); it.hasNext();) {

Object obj = (Object) it.next();

if(!temp.contains(obj))// --> contains()方法底层调用的是容器中元素对象的equals()方法!

//这里如果Person类自身不定义equals方法,就使用Objectequals方法,比较的就仅仅是地址了。

temp.add(obj);

}

list.clear();

list.addAll(temp);

}

}

LinkedList<E>类

    java.util.LinkedList<E>类是List接口的链表实现,可以利用LinkedList实现堆栈、队列结构。它的特有方法有如下这些:    

 

    addFirst();

    addLast();

    在jdk1.6以后:

    offerFirst();

    offerLast();

 

    getFirst():获取链表中的第一个元素。如果链表为空,抛出NoSuchElementException;

    getLast();

    在jdk1.6以后:

    peekFirst();获取链表中的第一个元素。如果链表为空,返回null

    peekLast();

 

    removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出NoSuchElementException

    removeLast();

    在jdk1.6以后:

    pollFirst();获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回null

    pollLast();

 

package ustc.maxiaolun.list.linkedlist;

 

import java.util.LinkedList;

 

public class LinkedListDemo {

 

public static void main(String[] args) {

//1.创建一个链表对象。

LinkedList link = new LinkedList();

 

//演示xxxFirst()xxxLast()方法。

 

//2.添加方法。

link.addFirst("abc1");

link.addFirst("abc2");

link.addFirst("abc3");

 

//3.获取元素。

System.out.println(link.getFirst());//abc3

System.out.println(link.getFirst());//abc3

 

//4.删除元素。

System.out.println(link.removeFirst());//abc3

System.out.println(link.removeFirst());//abc2

 

//5.取出link中所有元素。

while(!link.isEmpty())

System.out.println(link.removeLast());//removeFirst()

link.contains("abc3");//false

}

}

    练习:请通过LInkedList实现一个堆栈,或者队列数据结构。

 


 

下面给大家分享一下正厚软件对于软件测试的进阶课程大纲:

 

    2019正厚软件软件测试课程要点及大纲

 

 

2019正厚软件IT职能培训网报方式

 

如果需要详细了解试听或培训课程费用可留下 姓名+联系方式(手机号或微信号),我们会在第一时间为您解答服务!

 

软件测试零基础班

软件测试周末精品班

java开发班

ISTQB考试班

 

更多资讯尽在官方网站

www.njzhenghou.com

咨询热线
预约试听:025-86665061
官方公众号:ZhenghouSoft
技术热线:025-86665061
联系地址
南京总部:南京市鼓楼区湖南路16号5楼
重庆中心:重庆市渝中区投资大厦6楼
武汉中心:江夏区光谷智慧园16栋
微信公众号
联系我们
咨询热线:025-86665061
友情链接
Copyright © 2018 南京正厚软件 苏ICP备17057415号 网站地图 XML地图