黑马程序员——010——JavaAPI②(集合框架(List之ArrayList)、迭代器、枚举)

来源:互联网 发布:淘宝售后评价解释话术 编辑:程序博客网 时间:2024/05/20 18:17
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

集合框架
—Java的集合框架如下图所示:
这里写图片描述
—这就是集合框架的构成。由于数据结构的不同,有不同的集合,也叫容器。下面是集合类的简单介绍。
—①为什么出现集合类?
——面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
—②数组和集合类同是容器,有何不同?
——数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
—③集合类的特点
——集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
———————————————————————————
—和前面讲过的一些体系结构差不多,集合框架也是通过将共性向上抽取之后的的出来的体系,如下图:
这里写图片描述
—为什么出现这么多集合类呢:
——面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
——就相当于一个个的容器,因为每一个容器对数据的存储方式不尽相同,因此出现了这么多。而这种存储方式我们称之为“数据结构”。
———————————————————————————
集合框架的共性方法
—看共性方法当然要看根类Collection,就像上帝类bejct一样,包含所有类的共性方法方法;
—通过Collection的API我们知道它是从Java1.2开始出现的,那么功能无非就是“增删改查”,我们这里以ArrayList为例,演示共性方法:
———————————————————————————

/*Collection类,集合的共性方法*/import java.util.*;//导入集合类所在的包class Demo10_1{        public static void main(String[] args)        {                ArrayList list = new ArrayList();                //给集合添加元素                list.add("halo1");                list.add("halo2");                list.add("halo3");                list.add("halo4");                list.add("halo5");                //获取集合中元素的数量                System.out.println(list.size());//打印5        }}

———————————————————————————
—我们可以看到API中add方法的参数类型是个E,如下图:
这里写图片描述
——我们目前暂且可以理解成这里的E就代表Object;
—提醒:集合里面存的也是内存地址(对象的引用(地址));
—一些功能方法:
——int size():获取集合个数,集合的长度;
——boolean remove(“halo4”):删除元素halo4
——void clear():清空集合
——boolean contains(“halo3”):判断halo3是否在集合中存在
——boolean isEmpty():判断集合是否为空
——boolean retainAll(Collection c):保存在集合c中存在的元素,其他删除,相当于取交集;
——boolean removeAll(Collection c):移除集合c中存在的元素,其他不动;
——boolean addAll(Collection c):将指定的集合c中所有元素添加进来;
——boolean contains(Collection c):如果集合中包含集合c中所有元素,则返回true;
———————————————————————————
迭代器
—迭代器就是集合的取出元素的方式;
—Java中对集合取出的设计:
——当不足以用一个函数来描述,需要用多个功能来体现,所以就将取出这个动作封装成一个对象来描述。就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素。那么取出方式就被定义成了内部类。
——而每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都具有共性内容: 判断和取出。那么就可以将这些共性抽取。
——那么这些内部类都符合一个规则(或者说都抽取出来一个规则)。该规则就是Iterator。通过一个对外提供的方法:iterator();,来获取集合的取出对象。
——因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器了。
—实例比喻:夹公仔机,夹子就好比是迭代器,是公仔机这个类的一个内部类;
—小技巧示例:
———————————————————————————
——迭代器用完之后下文代码没有再次使用的话,应该让垃圾回收器回收空间,如下图:
这里写图片描述
———————————————————————————
———————————————————————————
List集合及其共性方法
我们先来Collection体系下的子类:
—①List:元素是有序的,元素可以重复,因为该集合体系有索引,也就是可以使用角标来方法元素;
—②Set:元素是无序的,元素不可以重复;
—我们以List接口为例:
——List完整类名是“java.util.List;”也就是使用它需要引入java.util包。
———方法有很多,这里不便于一一列出,大家自行查看API文档就能够看懂了!
———其中List特有的方法为:
————①E set(int index, E element):这里的E我们暂且认为Object
—————用指定元素替换列表中指定位置的元素(可选操作)。
————②List subList(int fromIndex, int toIndex) :表示类型描述,我们在稍后面的节会讲到,这里我们就认为E就是Object就可以了;
—————返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
—————这种设计到头尾的操作,在java中一般都是包含头不包含尾;
——由于List有索引,而Set没有,因此凡是能够操作角标的方法都是List体系的特有方法;
———①增
————boolean add(E e)
—————向列表的尾部添加指定的元素(可选操作)。
————void add(int index, E element)
—————在列表的指定位置插入指定元素(可选操作)。
———②删
————E remove(int index)
—————移除列表中指定位置的元素(可选操作),并且返回该元素的引用。
————boolean remove(Object o)
—————从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。
———③改
————E set(int index, E element)
—————用指定元素替换列表中指定位置的元素(可选操作)。
———④查
————E get(int index)
—————返回列表中指定位置的元素。
————List subList(int fromIndex, int toIndex)
—————返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
————int indexOf(Object o)
—————返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
————int lastIndexOf(Object o)
—————返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
————ListIterator listIterator()
—————返回此列表元素的列表迭代器(按适当顺序)。
————ListIterator listIterator(int index)
—————返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
———实例代码:
————将多个字符串存入List集合然后使用两种方法循环打印出所有元素:
———————————————————————————

/*将多个字符串存入List集合然后使用两种方法循环打印出所有元素:*/import java.util.*;//导入集合类所在的包class Demo10_1{        public static void main(String[] args)        {                ArrayList list = new ArrayList();                //给集合添加元素                list.add("halo1");                list.add("halo2");                list.add("halo3");                list.add("halo4");                list.add("halo5");                System.out.println("for循环遍历:");                //使用for循环遍历打印所有元素                for(int i=0;i<list.size();i++)                        System.out.println(list.get(i)); //使用get通过角标获取元素                System.out.println("迭代器遍历:");                //使用迭代器遍历打印所有元素                Iterator it = list.iterator();                while(it.hasNext())                        System.out.println(it.next());        }}

———————————————————————————
List体系也有的迭代器——ListIterator
—ListIterator接口针对List体系才出现的一个Iterator的子接口:
——其实例有底层给我们实现List,我们只需要调用这两个方法就可以获取了:
———ListIterator listIterator()
————返回此列表元素的列表迭代器(按适当顺序)。
———ListIterator listIterator(int index)
————返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
——ListIterator提供了比Iterator更丰富的对遍历List体系集合的功能:不仅能够正向遍历,还能逆向遍历,我们看下面的实例:
———————————————————————————

import java.util.*;//导入集合类所在的包class Demo10_2{        public static void main(String[] args)        {                //由于List是接口我们使用其子类ArrayList来new对象                List list = new ArrayList();                //给集合添加元素                list.add("halo1");                list.add("halo2");                list.add("halo3");                list.add("halo4");                list.add("halo5");                System.out.println("使用Iterator遍历:");                //并使用for循环,让变量it使用完被回收                for(Iterator it = list.iterator();it.hasNext();)                        System.out.println(it.next());                System.out.println("使用ListIterator正向再逆向遍历:");                //并使用for循环,让变量it使用完被回收                ListIterator it = list.listIterator();                while(it.hasNext())                        System.out.println(it.next());                while(it.hasPrevious())                        System.out.println(it.previous());        }}

———————————————————————————
运行结果:
这里写图片描述
从打印结果我们可以知道ListIterator中正向遍历逆向遍历用的是同一个指针;
———————————————————————————
注意:我们使用迭代器获取的时候不能够再使用get或者remove方法进行获取或删除,否则会引发以下异常:
这里写图片描述
此异常的API描述:其当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常;
———————————————————————————

import java.util.*;//导入集合类所在的包class Demo10_3{        public static void main(String[] args)        {                //由于List是接口我们使用其子类ArrayList来new对象                List list = new ArrayList();                //给集合添加元素                list.add("halo1");                list.add("halo2");                list.add("halo3");                list.add("halo4");                list.add("halo5");                System.out.println("使用Iterator遍历:");                //并使用for循环,让变量it使用完被回收                for(ListIterator it = list.listIterator();it.hasNext();)                {                        Object obj = it.next();                        System.out.println(obj);                        if("halo4".equals(obj))                        {                                //需要修改元素,使用ListIterator                                it.set("halo8");//把halo4改成halo8                                //我们想要迭代的遍历里为集合添加多一个元素                                list.add("halo9");//会抛异常                        }                }        }}

———————————————————————————
执行结果:
这里写图片描述
—所以在迭代时不可以通过集合对象的方法操作集合中的元素,不然会发生ConcurrentModificationException异常;
—另外在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作。如果还想要其他的操作如添加、修改等,就要使用其子接口ListIterator;并且该接口只能通过List集合的listIterator方法获取;
———————————————————————————
我们现在再来总结一下Collection体系关于List集合的部分:
Collection
|–List:元素是有序的,元素可以重复,因为该集合体系有索引;
|–ArrayList:底层的数据结构使用的是数据结构;特点:查询速度快,但是增删稍慢,并且是线程不同步的;
|–LinkedList:底层使用的是链表数据结构;特点;增删速度快,查询稍慢;
|–Vector:底层的数据结构使用的是数据结构;但是是线程同步的,从Java1.2开始被ArrayList代替。
———————————————————————————
在体系结构中我们发现Vector和ArrayList底层使用的都是数组结构,那么它们俩之间有什么样的关系:
—集合框架是在Java1.2才出现的,而Vector是Java1.0就有了,是线程安全的(早期版本的东西一般都是线程安全的),ArrayList则是Java1.2才出现的,线程不安全。我们知道线程安全都是需要判断锁的,因此这个升级是为了提高效率。
—提醒:
——通过ArrayList的构造函数的描述,我们发现ArrayList新建的时候会初始化容量为10,当ArrayList超过长度的时候,会new一个新的数组,以50%的长度延长,比如:10,满了不够之后就变成15了;
——而Vector超过长度的时候会以100%的长度延长,比如:10,满了不够之后就变成20了。
—因此Vector一般不用,因为即使线程不安全也可可以手动加锁;这就是为什么这个图里面没有Vector的原因了;
这里写图片描述
———————————————————————————
Vector中的枚举
尽管Vector类已经被ArrayList代替,但是其中还有特殊的地方要强调一下的。
—看到Vector的API方法列表中,如果我们仔细观察会发现,有很多方法都带有“Element”这个单词,这个就是Vector的特有方法:
———————————————————————————
—void addElement(E obj)
——将指定的组件添加到此向量的末尾,将其大小增加 1。
—E elementAt(int index)
——返回指定索引处的组件。
—E firstElement()
——返回此向量的第一个组件(位于索引 0) 处的项)。
—void insertElementAt(E obj, int index)
——将指定对象作为此向量中的组件插入到指定的 index 处。
—E lastElement()
——返回此向量的最后一个组件。
—void removeAllElements()
——从此向量中移除全部组件,并将其大小设置为零。
—boolean removeElement(Object obj)
——从此向量中移除变量的第一个(索引最小的)匹配项。
—void removeElementAt(int index)
——删除指定索引处的组件。
—void setElementAt(E obj, int index)
——将此向量指定 index 处的组件设置为指定的对象。
—Enumeration elements()
——返回此向量的组件的枚举。
———————————————————————————
我们以“Enumeration elements()”来演示:
—我们看到其返回类型又是一个新东西:Enumeration,枚举:
——其有两个方法:
———boolean hasMoreElements()
————测试此枚举是否包含更多的元素。
———E nextElement()
————如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
———看方法我们发现有点像迭代器,因此我们就可以知道枚举就是Vector特有的取出元素的方法,看下实例:
———————————————————————————

import java.util.*;class Demo10_4{        public static void main(String[] args)        {                //新建Vector集合                Vector v = new Vector();                //添加元素                v.add("halo1");                v.add("halo2");                v.add("halo3");                v.add("halo4");                //通过elements方法获取Enumeration枚举类                Enumeration en = v.elements();                while(en.hasMoreElements())                { //通过Enumeration枚举类的hasMoreElements方法获取元素                        System.out.println(en.nextElement());                }        }}

———————————————————————————
我们再查看Enumeration枚举类的API文档会发现其中有一段描述:
—注:此接口的功能与 Iterator 接口的功能是重复的。此外,Iterator 接口添加了一个可选的移除操作,并使用较短的方法名。新的实现应该优先考虑使用 Iterator 接口而不是 Enumeration 接口。
—其实枚举和迭代是一样的,因为枚举的名称以及方法的名称都过长,所以其被迭代器取代了,那么枚举类就这样郁郁而终了?
——并不是,IO流当中有一个对象也用到枚举了,jdk1.0开始,那时候没迭代器只有枚举,因此枚举类还是有它存在的价值;
那么Vector和ArrayList区别:
—Vector有枚举,ArrayList没有,因为ArrayList统一使用迭代器来操作元素了。
现在来做一些ArrayList的练习:
—练习:去除ArrayList中的重复元素;
实例代码:
———————————————————————————

import java.util.*;class Demo10_5{        public static void main(String[] args)        {                ArrayList al = new ArrayList();                al.add("java01");                al.add("java02");                al.add("java01");                al.add("java02");                al.add("java03");                al.add("java02");                sop(al);                al = singleList(al);                sop(al);        }        /*去重方法*/        public static ArrayList singleList(ArrayList al)        {                ArrayList newAl = new ArrayList();//定义一个新临时容器                //对参数进行遍历                Iterator it = al.iterator();                while(it.hasNext())                {                        Object obj = it.next();                        //如果临时容器中不存在该元素,则添加进去                        if(!newAl.contains(obj))                        {                                newAl.add(obj);                        }                }                return newAl;//最终返回临时容器即可得到去重后的集合        }        public static void sop(Object obj)        {                System.out.println(obj);        }}

———————————————————————————
—练习:将自定义对象Person作为元素存的ArrayList中,并去除重复元素,同名同年龄视为同一个人;
—提醒:ArrayList的contains方法判断元素是否相同使用的是equals方法,判断对象是否相同;而这里是自定义对象,ArrayList并不知道我们判断的条件是同名同年龄。我们必须重写person的equals方法即可;它会自动被调用的!
—实例代码:
———————————————————————————

import java.util.*;class ArrayListDemo{        public static void main(String[] args)        {                ArrayList al = new ArrayList();                al.add(new Person("lisi",31));                al.add(new Person("lisi",32));                al.add(new Person("lisi",30));                al.add(new Person("lisi",34));                al.add(new Person("lisi",30));                al.add(new Person("lisi",31));                sop(al);                al = singleList(al);                sop(al);        }        public static ArrayList singleList(ArrayList al)        {                //逻辑和上一个练习中的方法一致,这里就略了        }        public static void sop(Object obj)        {                System.out.println(obj);        }}/*自定义类*/class Person{        //成员变量        private String name;        private int age;        public Person(String name,int age)        {                this.name = name;                this.age = age;        }        //成员变量的set和get方法        public int getAge()        {                return this.age;        }        public String getName()        {                return this.name;        }        /*重写equals,告诉别人怎么样才是同一个人*/        public boolean equals(Object obj)        {                if(!(obj instanceof Person))                        return false;                Person p = (Person)obj;                return this.name.equals(p.getName())&&this.age==p.getAge();        }        public String toString()        {                return this.name+".."+this.age;        }}

———————————————————————————
注意:另外要注意的是remove方法也调用了equals方法,比如执行这句:
——al.remove(new Person(“lisi”,30));
——也会根据equals方法的返回值的true或者false来决定删除或者不删除元素。

1 0
原创粉丝点击