一.集合体系
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
数组和集合类同是容器,但是数组长度是固定的,数据类型也是固定的,集合类都是可变的。
下图是java中集合类的关系图。
上图是对集合类不停的向上抽取形成的继承体系。顶层为Collection接口
实现的两个常见子类接口
List和Set
List:可存放重复元素,元素存取是有序的。
Set:不可以存放重复元素,元素存取是无序的。
List又细分为ArrayList,LinkedList和Vector等
Set又细分为HashSet,TreeSet等。
具体的划分根据是其存储方式即数据结构。
二.Collection接口中常见的共性方法
以ArrayList为例:
ArrayList al=new ArrayList();
(1)添加元素
al.add("java");//添加元素,参数为泛型object,以便于接收任何类型的对象,另外集合中保存的是对象的地址,而不是对象本身。
a1.addAll();添加指定集合的全部。参数为集合
al.size();//集合长度。
(2)删除元素
al.remove("java");
al.clean()清空集合
(3)判断元素。
al.contains("java");返回boolean型
al.isEmpty();
(4)取交集
retainAll();参数为集合,保留与指定集合的交集部分。
(5)获取元素
集合中元素的获取主要是通过迭代器完成的。
集合的iterator()该静态方法可以获取到一个Iterator迭代器接口的子类对象。该子类有几个方法用于取出集合中的元素。说是静态方法其实是集合存在一个静态内部类,因为要直接访问集合内容的元素所以定义在集合内部,迭代器接口只是对集合内部类中的共性抽取,从而使所有集合的元素操作规则的统一,同时在集合内部定义静态方法iterator()来获取内部类的对象。通过多态使其父类接口Iterator引用指向子类内部类对象。
使用方法:
(a)
for(Iterator iter = iterator();iter.hasNext(); )
{
System.out.println(iter.next());
}
(b)
Iterator iter = l.iterator();
while(iter.hasNext())
{
System.out.println(iter.next());
}
迭代器使用的注意事项
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
迭代器的next方法返回值类型是Object,所以要记得类型转换。
三.List接口即其子类。
ArrayList;底层数据结构就是数组结构;查询修改速度很快根据索引完成,但是增删慢,因为一个位置变动其他位置都要顺次移动。
LinkedList;底层数据结构是链表结构;增删速度很快,断开连接重建连接,查询很慢,因为需要从头开始逐个元素对象访问,不是根据索引。
Vector底层是数组结构与ArrayList一致,是老版本存在的被替代了,线程是同步的,ArrayList是不同步的,多线程时需要手动加锁。同步会降低效率。同时Vector默认的数组长度为15,ArrayList默认的数组长度为10更节省资源。
List集合中元素是有序的,元素可以重复,该集合体系元素是有索引的。有索引所以可以根据索引进行操作,具有索引元素的特有方法。当然因为索引的存在List集合也可以通过遍历获取所有元素,不局限于迭代器。
需要注意的是ListIterator迭代器与Iterator迭代器的不同,前者是后者的子类,包含后者的获取功能但是又有自己的特有功能。比如Iterator迭代器不能对元素进行并发的操作,即在对元素进行取出的时候,同时又对元素进行修改,迭代器与集合自身的方法同时对一个元素进行操作发生冲突就会抛出并发异常。而子类接口ListIterator封装了对应的修改方法可以避免这种不安全性。
共性方法:
(1)增
add(index,elements)
addAll(index,collection)
(2)删
remove(index)
(3)改
set(index,element)
(4)查
get(index)
subList(from,to)
listIterator();
indexof(element)
lastIndexOf(element)
LinkedList:
特有方法与其数据结构有关,因为是手拉手的链表结构所以其首尾元素的操作比较多。
addFirst(element);首位添加
getFirst();首位获取
addLast(element);尾位添加
getLast();尾位获取。
removeFirst();获取首位元素同时删除元素
removeLast();获取尾位元素同时删除元素//当元素为空的时候会抛出异常。
pollFirst();1.6版本新特性,与removeFirst方法相同,但是当元素为空的时候不会抛异常,返回值为null
pollLast();
peakLast();代替getLast
peakFirst();
Vector:
需要注意的一点;枚举方法。枚举是Vector的特有取出方式
枚举与迭代其实是一样的,但是因为枚举的名称和方法都过长所以被取代了。
Vector v=new Vector();
Enumeration en=v.elements();//用法与迭代器一样。
while(en.hasMoreElements()){
sop(en.nextElement());
}
三.Set接口及其子类
Set集合的功能与List集合是一致的,只不过是无序的方法中没有对元素脚标的操作。此出的无序是指相对于存储时的先后顺序而言的。
HashSet:
底层数据结构就是哈希表。,存储时是按其哈希值决定顺序的。
元素进行存储的时候,首先是调用hashcode方法返回哈希值用来指代地址值,先和已有元素进行哈希值的比较即地址值的比较,如果地址值一样,则继续比较对象内容的值进行比较即调用equals方法进行比较,相同则add方法添加失败,如果不同则在原地址建立分支,如果地址值不一样,则直接进行存储而不再调用equals方法。所以对对象进行存储时一般都需要重写hashcode和equals方法,因为默认的方法并不能符合要求。
同样进行删除和判断的时候步骤也是与上面相同。以上在过程中调用的方法大都是元素对象自己的方法可以是继承自Object类也可以是自己或者实现的接口
TreeSet:
底层数据结构为二叉树结构,可以对Set集合中的元素进行排序。默认为自然排序,让元素自身具有比较性。第一个添加的对象元素作为树根,然后后面的对象元素与其进行比较,大的放在一边小的放在另一侧,再添加元素与第一个比较,如果需要再与第二个比较决定位置,就这样一次比较下去。二叉树的数据结构可以优化比较次数从而提高性能。当元素过多,二叉树体系过大的时候则自动取其折中值作为第一个比较值。
另外因为比较的结果都是由compareTo方法返回值决定的,所以可以强制让conpareTo方法只返回一个值,使其按照存入的顺序进行排列。 返回0则只能存入一个元素。这种方式就可以对集合进行存入的正序或者倒序存储。
当该集合进行存储元素的时候,为了排序会调用comparable接口用来进行自然排序。类的caompareTo被称为自然排序方法。所以在存储之前元素对象为了具有比较性需要实现comparable接口并且重写自定义compareTo方法,先按照主要条件排序,当主要条件相同时判断次要条件。
TreeSet第二种排序方式,当元素自身不具备比较性时,或者所需要的比较性不是所需要的规则,这时就需要让集合自身具备比较性。通过构造函数构造comparator比较器来指定排序方式。
TreeSet ts=new TreeSet(new Compare());
class Compare implements Comparator{//构造器的封装通过实现Comparator接口,覆盖compare方法然后将子类构造器对象当做参数传入集合构造函数。
public in compare(Object o1,Object o2){
Student s1=(Student)o1;
Student s2=(Student)o2;
return s1.getName().compareTo(s2.getName());
}
}
四.Map及其子类
该集合存储键值对,是一对一对往里存,而且要保证键的唯一性。
map集合体系
Hashtable;底层是哈希表数据结构,不可以存入null作为键值键或者键值,该集合是线程同步的。效率低
HashMap;底层是哈希表数据结构,并允许null作为键值键或者键值,该集合是不同步的。效率高
TreeMap;底层是二叉树数据结构,线程不同步,可以用于给map几何中的键进行排序。
和set很像,其实set底层就是使用了map集合。
map共性方法
添加
put(key,value)//当存在键值键相同的时候,后添加的值会覆盖原有的键对应的值,并返回被覆盖键值,类似调用了一次remove方法。
putAll(Map<?extends key,?extends Value> m)
删除
clear()
remove(Object key)//删除的同时返回键值
判断
containsKey(Object key)
containsValue(object value)
isEmpty();
获取
get(object key)//返回null时说明不存在
size()
values()//获取map集合中所有的值,返回的是一个collection<v>的集合.
entrySet()
keySet()
Map集合的两种取出方式,map集合中没有迭代器,将map集合转换成set集合再通过迭代器取出
1,keySet
Set<key> keySet返回此映射中包含的键的Set集合,而set集合具有迭代器,所以可以以迭代的方式取出所有的键,根据get方法获得对应的键值
2,entrySet
Set<Map.entry<K,V>> entrySet();将map集合中的映射关系存入到set集合中,该类型是Map.Entry映射关系类型键值对,然后再通过迭代器取出关系类型对象Map.Entry<K,V>是一个接口,其中有getKey和getValue方法取出对应的键和键值。原理类似迭代器,只不过Entry是个内部接口,通过map集合子类实现接口来对功能进行定义。
五.扩展
1,集合框架中的工具类
Collections
• 对集合进行查找
• 取出集合中的最大值,最小值
• 对List集合进行排序
• ……
Arrays
• 将数组转成List集合
• 对数组进行排序
• 对数组进行二分查找
2,
增强for循环
1.5版本以后对迭代器的封装
for(数据类型 变量名:被遍历的结合或者数组)用来遍历集合,
for(String s:al){}不同于迭代器,对于集合的遍历此循环只能执行取出的操作。迭代器除了遍历还可以进行remove集合中元素的动作。如果使用ListIterator迭代器还可以进行增删改查的动作。
对于传统for高级for有个局限性,必须要有被遍历的目标。建议在遍历数组的时候还是使用传统for,因为传统for可以定义脚标。