申明:
实习生的肤浅理解,如发现有错误之处,还望大牛们多多指点
废话
其实我写java的后台操作,我每次都会遇到一条语句:List<XXXXX> list = new ArrayList<XXXXX>();
但是我仅仅只是了解,list这个类是一个可变长用来存储的对象实例的类,我甚至觉得这个List对象可以理解成数组,但是却又与java中咱们正常理解的数组很多的不同,比如说,他的长度可以随着需要自动增长,比如说,实例化一个List类就和咱们声明数组的时候是不一样的!
今天的实习生活过的有点枯燥,我就打开了eclipse,看同事们写的代码,无意间又看到了这句话,所以决定学习一下这一类的操作——java中的容器类(集合类)
正文
先偷个图来吧,我不会告诉你我是在百度百科里面偷的
如何,我们可以看出,java中的集合操作主要有两大类:Collection集合与Map映射Collection
Collection是一个顶层的接口,他是java集合的一个抽象,在此基础上派生出了两个子接口,分别为:List与Set
List
List接口,特点有序的,所存储的对象可以为null,并且允许重复,这点与set有很大区别,Set是不允许重复的,List很类似于数组,对于List对象的访问可以通过类似于数组下标去访问,但是是通过get(int index)方法进行访问的,同时其实际长度也很类似于数组,可以通过size()返回其实际长度 ,除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。 list常见方法::向列表的尾部添加指定的元素
add(E e)
: 在列表的指定位置插入指定元素
add(int index,E element)
:添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序
addAll(Collection<? extendsE> c)
: 将指定 collection 中的所有元素都插入到列表中的指定位置 与数组相比较,list的查询效率 高,但是插入和删除的效率较低,因为插入和删除会引起其他元素的位置变化
addAll(int index,Collection<? extends E> c)
:从列表中移除所有元素
clear()
:如果列表包含指定的元素,则返回true
contains(Object o)
:如果列表包含指定 collection 的所有元素,则返回true
containsAll(Collection<?> c)
: 返回列表中指定位置的元素
get(int index)
:返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1
indexOf(Object o)
: 返回按适当顺序在列表的元素上进行迭代的迭代器
iterator()
:返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1
lastIndexOf(Object o)
:返回此列表元素的列表迭代器(按适当顺序)
listIterator()
:返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始
listIterator(int index)
: 移除列表中指定位置的元素
remove(int index)
:从此列表中移除第一次出现的指定元素
remove(Object o)
: 从列表中移除指定 collection 中包含的其所有元素
removeAll(Collection<?> c)
: 仅在列表中保留指定 collection 中所包含的元素
retainAll(Collection<?> c)
:用指定元素替换列表中指定位置的元素
set(int index,E element)
:返回列表中的元素数
size()
返回列表中指定的fromIndex(包括 )和 toIndex(不包括)之间的部分视图
subList(int fromIndex,int toIndex)
toArray()
:返回按适当顺序包含列表中的所有元素的数组
详细方法信息还是参考一下API里面的吧 实现list接口的主要有:ArrayList、LinkedList、Vector和Stack
ArrayList
通过名字就能知道这是个啥了吧,灰常类似于数组
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步,仅有Vector实现了同步(线程安全),每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小,默认值好像是10。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法(设定长度最小值)来增加ArrayList的容量以提高插入效率。和LinkedList一样,ArrayList也是非同步的(unsynchronized)
案例:
package test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
public static int flg = 0;
public int self = 0;
public Test() {
++flg;
self = flg;
System.out.println("已经初始化了:" + flg + "个实例");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
* 加入范式Test表示这里存储Test类型,并且可以获得具体值之后,可以访问对象的方法和属性 比如下述:list.get(i).flg
* 若不添加范式,则无法访问该self属性或者其他方法
*/
List<Test> list = new ArrayList<Test>();
for (int i = 0; i < 5; i++) {
list.add(new Test());
System.out.println(list.get(i).self);
}
list.add(new Test());
System.out.println(list.get(list.size() - 1).self);
list.addAll(list);
System.out.println(list.size());
list.add(0, null);
System.out.println(list.get(0));
// 使用迭代器去遍历,注意给迭代器添加一个泛型
Iterator<Test> myiterator = list.listIterator();
Test test;
while (myiterator.hasNext()) {
test = myiterator.next();
if (test != null)
System.out.println(test.self);
else
System.out.println(test);
}
}
}
LinkedList
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque),该类实现了Deque接口,提供了add和poll方法实现FIFO先进先出的队列操作,一起其他的堆栈和双向队列操作。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
案例:
基础操作
<span style="font-size:14px;">package test;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Test {
public static int flg = 0;
public int self = 0;
public Test() {
++flg;
self = flg;
System.out.println("已经初始化了:" + flg + "个实例");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
* 加入范式Test表示这里存储Test类型,并且可以获得具体值之后,可以访问对象的方法和属性 比如下述:list.get(i).flg
* 若不添加范式,则无法访问该self属性或者其他方法
*/
List<Test> list = new LinkedList<Test>();
int i = 0;
Test test = new Test();
list.add(0, test);
while (i < 5) {
list.add(new Test());
i++;
}
System.out.println("indexOf :" + list.indexOf(test));
System.out.println("lastIndexOf :" + list.lastIndexOf(test));
System.out.println("contants :" + list.contains(test));
System.out.println("contants :" + list.contains(new Test()));
// 注意迭代器的使用,给迭代器指定正确的泛型,才可以访问详细的属性和方法
Iterator<Test> iterator = list.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next().self);
}
}
}</span>
至于大家都说了LinkedList可以当做队列或者堆栈,从表面上,LinkedList实现了Deque等接口,确实可以这么去用了,但是我在实践的过程中,我得到的LinkedList的实例,不知道怎么情况,没有api里面给出的poll方法,所以我这里没有做关于这个的案例的,但是模拟还是很简单的
Vector
Vector类似于ArrayList,但是确实同步的,也就是说他是线程安全的,换句话说就是如果Vector创建了一个迭代器,那么这个迭代器正在使用的时候,另一个线程改变了这个Vector的状态,那么就会产生异常 用法接近ArrayList,参照上述以及API即可Stack
栈这个东西,在数据结构里面学过的,以前很熟悉,可是现在我就陌生了,大概的知道这个有一个特性:LIFO后进先出,在java中Stack是基于Vector的,除了基本的方法push()和pop()方法,java的Stack还提供了一个peek()获取栈顶元素值的方法,empty方法判断是否为空,search方法寻找某个元素在栈中的位置等 既然实现了List接口,那么就会有list的一些操作方法 简单案例:
package test;
import java.util.Stack;
public class Test {
public static int flg = 0;
public int self = 0;
public Test() {
++flg;
self = flg;
System.out.println("已经初始化了:" + flg + "个实例");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Stack stack = new Stack();
for (int i = 0; i < 5; i++)
stack.push(i);
System.out.println(stack.peek());
System.out.println(stack.size());
int len = stack.size();
for (int i = 0; i < len; i++)
System.out.println(stack.pop());
System.out.println(stack.size());
}
}
Set
Set是一种不可重复的Collection接口,set的检索效率相对较低,而与list对比,插入和删除的效率较高,不会引起其他元素位置的变化,Set是无序的,Set和List最大的区别是Set不允许重复
我们重点要记住这家伙不能重复
Set不允许重复的原因是,他是基于Map实现的,而Map中的key是不允许重复的,Set中使用的仅仅是Map中的key
Set常见的方法,详细情况请参考Java语言的API
add(E e) :如果 set 中尚未存在指定的元素,则添加此元素
addAll(Collection<? extendsE> c) :如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中
clear() :移除此 set 中的所有元素
contains(Object o) : 如果 set 包含指定的元素,则返回true
containsAll(Collection<?> c) :如果此 set 包含指定 collection 的所有元素,则返回true
equals(Object o) :比较指定对象与此 set 的相等性
isEmpty() :如果 set 不包含元素,则返回true
iterator() :返回在此 set 中的元素上进行迭代的迭代器
remove(Object o) : 如果 set 中存在指定的元素,则将其移除
removeAll(Collection<?> c) :移除 set 中那些包含在指定 collection 中的元素
retainAll(Collection<?> c) : 仅保留 set 中那些包含在指定 collection 中的元素
size() :返回 set 中的元素数
toArray() :返回一个包含 set 中所有元素的数组
比较蛋疼,set中是没有get方法获取元素对象的,只能通过迭代器来访问数据
我们常见的Set实现类有:TreeSet、HashSet和LinkedHashSet
TreeSet
TreeSet居然是有序的,默认是自然序列的,排序方式可以使用自带的,也可以使用自定义,在创建TreeSet的时候,传递一个自定义的排序规则对象即可,另外既然它是有序的,有是基于TreeMap实现的,那么TreeSet中的元素对象必须实现Comparable接口,但是如果是字符串对象的话,呵呵,不需要了,String本身就已经实现了Comparable接口了 很显然,在测试过程中没有发现get方法,看到了iterator方法,那么也就意味着,只能通过迭代器访问详细数据了 简单案例: 需要实现Comparable接口(String不需要,String已经实现了,不过你可以重新写一个,用自己定义的)
package test;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class Test implements Comparable<Test> {
public static int flg = 0;
public int self = 0;
public Test() {
++flg;
self = flg;
System.out.println("已经初始化了:" + flg + "个实例");
}
@Override
public int compareTo(Test o) {
// TODO Auto-generated method stub
if (this.self < o.self)
return -1;
else if (this.self > o.self)
return 1;
else
return 0;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Set set = new TreeSet();
for (int i = 0; i < 5; i++)
set.add(new Test());
System.out.println(set.size());
Iterator<Test> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next().self);
}
}
}
HashSet
和TreeSet一样只能通过迭代器来访问数据,HashSet是基于HashMap实现的,但是是无序的,常用的方法和Set接口的相近,记住一点,访问必须通过迭代器,迭代的顺序不能保证是和插入的顺序一致,这点与LinkedHashSet正好是相反的
案例:有待补充
LinkedHashSet
LinkedHashSet是一个链表结构,与上述一致,通过迭代器遍历,但遍历的顺序和插入的顺序一致
案例:有待补充
Map
(其实我接触Map应该是从学习Hibernate课堂上,老师说过,学java的时候,老师讲到基本循环结构就结束课程了,要命,呵呵)Map是一个顶层接口,主要是处理映射(key/value)类型,用于存储键值对的Map接口提供了三种Collection视图,允许以键集、值集或者键值对映射关系集的方式来访问某个映射的内容,迭代的顺序定义为迭代器在collection视图上返回的元素顺序,有些Map实现可以确保顺序,比如TreeMap,但有些是不可以的,比如HashMap构造方法:构造方法一般有两种:一种是无参数,另一种是带一个Map类型的参数常用方法:put方法,添加键值对,这里对于Map的介绍,还是以例子为主吧。实现Map接口的主要有TreeMap、HashMap等TreeMap
基于红黑树(Red-Black tree)的 NavigableMap 平衡二叉树实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
构造函数: TreeMap() :使用键的自然顺序构造一个新的、空的树映射
TreeMap(Comparator<? super K> comparator) 构造一个新的、空的树映射,该映射根据给定比较器进行排序
TreeMap(Map<? extends K,? extends V> m) 构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序 进行排序
TreeMap(SortedMap<K,? extends V> m) 构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射
常用方法 Map.Entry<K,V> ceilingEntry(K key)
返回一个键-值映射关系实体,与大于等于给定键的最小键关联;如果不存在这样的键,则返回 null
get(Object key) :返回指定键所映射的值,如果对于该键而言,此映射不包含任何映射关系,则返回 null
keySet() :返回此映射包含的键的 Set 视图
navigableKeySet() :返回此映射中所包含键的 NavigableSet 视图
values() :返回此映射包含的值的 Collection 视图
put(K key, V value) :将指定值与此映射中的指定键进行关联
putAll(Map<? extends K,? extends V> map) :将指定映射中的所有映射关系复制到此映射中
remove(Object key) :如果此 TreeMap 中存在该键的映射关系,则将其删除
HashMap
基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)
详细信息,还是API比较全,晚上看累了,不想写了