在类集之前,想保存数组的话就只能是使用对象数组。但是数组有长度的限制,而如果使用链表这种数据结构的话,又会比较麻烦。类集框架就是来解决上面的问题的,就是实现一个动态的数组,包装上数据结构,因此就会有类集的出现。类集接口有collection,map,List,set,Iterator,ListIterator,Enumeraation,
SortedMap,Queue,Map.Entry,在面试时就会经常遇到前面四个的问题。
一、Collection接口
Collection接口的定义如下
public interface Collection<E> extends Iterable<E>
从接口的定义可以看出来,这里是使用的泛型的定义,避免发生ClassCastException的异常。Collection接口是单值的存放最大父接口,可以向其中保存多个对象。继承于Iterable接口,Iterable接口已经是最大的接口了, 它主要是告诉我们它是可以进行迭代的。
public interface Iterable<T> {
Collection接口的所有方法如下:
/*2017/11/3:这两天在看码的时候才注意到一个小细节,那就是这个集合定义的许多方法都是返回的boolean类型,之前都没有注意到过。看下面的代码,其中的一个add方法,增加值的时候是这样增加的,先把这个list的容量加1,然后把数据才赋进去,前面两步没有问题的时候才会返回true,表面增加成功。源码中大部分的方法都是这样的。*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
遍历Collection接口,不论Collection的实际类型如何,因为他是继承于Iterable接口,所以它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素:
Iterator it=collection.iterator();//获得一个迭代子
while(it.hasNext()){
Objectobj=it.next();//得到下一个元素
}
也可以使用foreach输出
for(元素类型t 元素变量x : 遍历对象obj){
引用了x的java语句;
}
for (String x : list) {
System.out.println(x);
}
Collection接口虽然是集合的最大接口,但是如果直接使用Colllection接口进行操作,则表示操作的含义不明确,因此会一般使用他的子接口。Collection的子接口有List,Set,Queue,和SortedSet四个。List可以存放重复的内容,Set不能存放重复的内容,所有重复的内容靠hashCode()和equals()两个方法区别。
二、List接口
List是Collection的子接口,其中可以保存各个重复的内容。接口的定义:
public interface List<E> extends Collection<E>
List接口扩充了Collection接口,拥有比其更为广泛的方法,List接口的所有扩展方法如下:
1、ArrayList子类
ArrayList子类可以为List接口进行实例化。ArrayList继承了AbstractList类,
public class ArratList<E> extends AbstractList<E> implements List<E> ,RandomAccess,Cloneable,Serializable
而AbstractList类实现了List接口。
public abstract class AbstractList<E> extends AbstractCollection <E> implements List<E>
因此可以直接使用ArrayList为List接口进行实例化。
public class ArrayListAdd {
public static void main(String []args){
List<String> allList=new ArrayList<String>();
Collection<String> allCollection=new ArrayList<String>();
allList.add("hello");
allList.add(0,"world");//在0位置添加元素
System.out.println(allList);//[world, hello]
allCollection.add("hi");
allCollection.add("MLDN");
allList.addAll(allCollection);//在最后添加元素
allList.addAll(0, allCollection);//在0位置添加元素
System.out.println(allList);//[hi, MLDN, world, hello, hi, MLDN]
}
}
每一个list都会被赋一个初始的容量,初始容量为10
/**
* Constructs an empty list with an initial capacity of ten.
*/
从上面的结果可以看出来,使用List中的add(int index,E)方法可以在集合中的指定位置增加元素,而add(E)只是在最后面添加。
remove()方法可以去除指定位置的元素,或者去除指定内容的元素。
allList.remove(0);//移除
System.out.println(allList);//[MLDN, world, hello, hi, MLDN]
allList.remove("MLDN");
System.out.println(allList);//[world, hello, hi, MLDN]
allList.remove("MLDN");
System.out.println(allList);//[world, hello, hi]
每次可以去除一个对象remove(Object o),每次去除一组对象removeAll(Collection<?> c),如果有多个相同类型的元素则需要多次去除;
通过取得长度的方法size(),然后使用get()方法可以将集合的指定位置的内容输出。
System.out.println(allList.size());//3
System.out.println(allList.get(1));//hello
通过头Array()方法可以将集合变为数组。以及截取集合subList(int,int)方法,是否为空isEmpty()方法,查找字符串位置indexOf(String)方法等。
2、Vector子类
Vector子类是比较老的一个类了,同样是继承于AbstractList<E>接口,
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
因为和arraylist的区别不大,测试代码就不写了,arraylist是异步处理,是非线程安全的,只能使用Iterable和foreach输出。而Vector是同步出来,是线程安全的,可以使用Iterable,Enumeration和foreach输出
3、Linkedlist
LinkedList是一个链表的操作类,定义如下
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
这个类不仅实现了list接口还实现了Duque接口,双向队列(Deque),是Queue的一个子接口,双向队列是指该队列两端的元素既能入队(offer)也能出队(poll),如果将Deque限制为只能从一端入队和出队,则可实现栈的数据结构。对于栈而言,有入栈(push)和出栈(pop),遵循先进后出原则,Queue接口是队列接口,是先进先出的方式。也就是说LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用.
public interface Deque<E> extends Queue<E> {
/**A linear collection that supports element insertion and removal at
* both ends. The name <i>deque</i> is short for "double ended queue"
最后Queue接口是实现了Collection接口
public interface Queue<E> extends Collection<E> {
通过上面可以看到LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用.这个类的两个构造方法
public LinkedList() {
}//生成空的链表
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}// 复制构造函数
其实现的方法也比较多,这里就不一一介绍了,需要用的时候查一下就行了。
三 set接口
set接口也是collection接口的子接口,但是和他们不一样的地方就是它不能包含不一样的重复的对象元素。
1、HashSet子类
hashset是set接口的子类,存放的元素是无序但不可重复。
public static void main(String[] args) {
// TODO 自动生成的方法存根
Set<String> allSet=new HashSet<String>();
allSet.add("a");
allSet.add("a");
allSet.add("b");
allSet.add("b");
allSet.add("b");
allSet.add("c");
allSet.add("f");
allSet.add("s");
allSet.add("d");
System.out.println(allSet);//调用tostring()方法
}
输出[a, b, c, s, d, f]
2、TreeSet子类
TreeSet子类是set接口的子类,存放的元素是有序而且也不可以重复。这里的有序是指在输入数据以后他会进行一个自动的排序。
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
他是继承了AbstractSet类,AbstractSet类又实现了Set接口
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
下面是最简单的一个TreeSet的测试
Set<String> allset=new TreeSet<String>();
allset.add("s");
allset.add("a");
allset.add("a");
allset.add("b");
allset.add("b");
allset.add("b");
allset.add("c");
allset.add("f");
allset.add("s");
allset.add("d");
System.out.println(allset);
输出结果
[a, b, c, d, f, s]
TreeSet的排序看起来就是这样,它会将所有非重复的元素就行排序,然后存储起来。我们看它的源码,在调用add方法以后,首先通过判断已经存储了这个值,然后他会返回一个boolean值。
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
未完待续。。。。