java集合的基本方法的使用与测试(一)
集合是Java开发中经常使用的一种框架,当然他底层是各种数据结构实现的,很值得我们为其驻足!
数组与集合的比较
数组 : 一旦初始化数组时指定了长度,长度不可变
缺点:不能保存数量不确定的数据,不能保存具有映射关系的数据。
集合:也称容器类,都是Java.util包下的,可以用于存储数量不等的多个对象,实现了常用的数据结
构,如栈(Stack,先进后出)、队列(Heap,先进先出)等。还可以用于保存具有映射关系的关联数据。
区别:数组元素可以是基本型,也可以是对象,即引用型,但只能存同一类型。而集合只能保存引用型,
支持类型不同,但规定泛型后,只能是该类型;一般集合中只放一种类型(原因 在使用时集合中的元素各不
同,不方便使用),由泛型 <> 规定。基本型拥有对应的包装类,可以自动拆装箱。
集合中存放的是多个对象的引用,对象本身还是放在堆内存中。
Scanner sc = new Scanner(new File("file\\1.png"));
List l = new ArrayList();
l.add("妖怪,嘿!");
l.add(new Integer(1));
l.add(sc);
for (Object object : l) {
//???不知每个该转何种类型
}
所以劝自己为善,不要为难人家“胖虎”!
在创建集合对象时,在<>内表明集合要放的对象的类型。
分类:
collection(List,Set,Queue也是接口)、Map 两种体系,也是两个接口,派生出多个实现类或者接口。
下图是一些常用的集合:
List(也称序列):可存重复值的集合,有下标,维护存入和取出顺序。
Set:不可重复的集合,无下标,不维护存入和取出顺序。
类似于罐子,放入和取出顺序不定。(但为某种固定的某种顺序,因为每次存入算法一样)
Map:有映射关系的集合,key值不可重复,用于标识value值,value值可以重复
类似于药橱柜 ,每个抽屉都有标签。但不同的在于
Iterator(迭代器):该接口也是集合框架的成员,用来遍历(迭代访问)Collection系列集合的元素。除了
Map系列的集合,都实现了Iterator接口。
注意 点:
在迭代时,不能通过集合的remove方法改变集合中的元素
可以通过Iterator的remove方法,改变集合中的元素。
代码如下:
public static void main(String[] args) {
List<String> csp = new ArrayList<String>();
//附上大名,嘻嘻
csp.add("草 ,长已无她");
csp.add("水 ,平心却荡");
csp.add("平 ,萍更相依");
csp.add("嘻,声不再有");
//得到专用的迭代器
Iterator<String> iterator = csp.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
//注意:
//在迭代时,不能通过集合的remove方法改变集合中的元素
//可以通过Iterator的remove方法,改变集合中的元素。
// csp.remove(0);
iterator.remove();
}
//迭代完后,查看集合中元素的个数
System.out.println("集合我这么长:"+csp.size());
}
结果:
List接口中
ArrayList:
1.实现了List接口,它是大小可变(自动增长)的类型Object数组,有下标,所以遍历快,插入或删除慢,
允许存入null.
基本操作:
//ArrayList实现了Iterable<E>接口,可以用Iterator来遍历
//Cloneable接口(标记性接口)
// () 放参数列表
List<String> ch = new ArrayList<String>();
//往集合里add元素
ch.add("锄");
ch.add("禾");
ch.add("日");
ch.add("当");
ch.add("午");
//三种遍历方式中的第一种遍历方式,普通for
for (int i = 0; i < ch.size(); i++) {
//根据List有下标,通过下标得到集合中的元素
//下标从0开始
System.out.println(ch.get(i));
}
System.out.println("=====漂亮的分隔线=====");
//删除集合种元素
ch.remove(0);//该方法会返回被删除的元素
//另有 remove(Object o) 删除集合中首次出现的该元素
//三种遍历方式中的第二种遍历方式,增强for(即foreach)
for (String mn : ch) {
System.out.println(mn);
}
System.out.println("=====华丽的分隔线=====");
//查找元素
boolean ri = ch.contains("日");
System.out.println("有ri?"+ri);
//改,指定下标处的元素
ch.set(3, "NO!");
System.out.println("看看我的长度===="+ch.size());
System.out.println("=====俺you来了=====");
//三种遍历方式中的第三种遍历方式,集合专用的迭代器
//得到该集合专用的迭代器
//hasNext()和next()成对使用,前者判断是否有下一个元素,后者得到下一个元素
Iterator<String> weri = ch.iterator();
while(weri.hasNext()){
System.out.println(weri.next());
}
}
运行结果如下:
2.线程不安全。在集合工具类Collections,有能够将集合变为安全集合的方法synchronizedXxx()方法,
详情请参考API开发手册。
3.实现了Cloneable接口,该接口是标记性接口,能够实现浅克隆,即用Object类中clone()方法。
而ArrayList中重写了clone()方法。在Object中clone()方法是protected,子类继承后能重写该方法,其访问权
限要大于等于父类的访问权限。
测试clone()方法:
// “==” 比较引用型时比地址
ArrayList<Integer> csp = new ArrayList<Integer>();
//声明Integer对象
Integer integer1 = new Integer("1");
Integer integer2 = new Integer("2");
Integer integer3 = new Integer("3");
//加入csp集合
csp.add(integer1);
csp.add(integer2);
csp.add(integer3);
//clone返回object类型,而csp为ArrayList类型,故须类型转换
ArrayList<Integer> clone = (ArrayList<Integer>)csp.clone();
//比较两个集合的地址
System.out.println(csp == clone);
for (int i = 0; i < clone.size(); i++) {
//得到集合clone元素的值
int temp1 = clone.get(i);
//得到集合csp元素的值
int temp2 = csp.get(i);
//比较值的大小
System.out.println(temp1 ==temp2 );
}
for (int i = 0; i < clone.size(); i++) {
//比较对应元素的地址
System.out.println(clone.get(i) == csp.get(i));
}
该过程示意图:
4.实现了Serializable接口,能够进行深克隆。
测试深克隆:
public class DeepCloning implements Serializable{
//实现Serializable接口,标记性接口,实现了该接口才能进行深克隆
private static final long serialVersionUID = -4893294338233688244L;
public static void main(String[] args) {
ArrayList<Integer> csp = new ArrayList<Integer>();
//声明Integer对象
Integer integer1 = new Integer("1");
Integer integer2 = new Integer("2");
Integer integer3 = new Integer("3");
//加入csp集合
csp.add(integer1);
csp.add(integer2);
csp.add(integer3);
//输出
ObjectOutputStream oos = null;
try {
oos= new ObjectOutputStream(new FileOutputStream("caoshuiping"));
oos.writeObject(csp);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//读入
ObjectInputStream ois = null;
ArrayList<Integer> cspClone = null;
try {
ois = new ObjectInputStream(new FileInputStream("caoshuiping"));
try {
cspClone = (ArrayList<Integer>) ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//比较
System.out.println(csp == cspClone);
for (int i = 0; i < csp.size(); i++) {
System.out.println(csp.get(i) == cspClone.get(i));
}
}
结果:
示意图:
LinkedList:
1.实现了List接口,它是连接列表(双向链表),有指针,所以遍历慢,删除或插入快,允许存入null。
2.线程不安全。在集合工具类Collections,有能够将集合变为安全集合的方法synchronizedXxx(),方法,详
情请参考API开发手册。
3.也实现了Cloneable接口,能够进行浅克隆。
4.实现了Serializable接口,能够进行深克隆。
简单的增删查改相似。
A L 区别:
1.ArrayList为数组遍历快,插入或删除慢;LinkedList为链表遍历慢,删除或插入快.
2.ArrayList实现了RandomAccess接口,表明它支持快速随机访问,即用for遍历比用迭代器快。
3.(使用小建议)假如没有甚麽特殊要求,一般用ArrayList;LinkedList实现了Deque<>,和Queue<>(队列)接口,若要模仿特殊的结构则用LinkedList。
4.在声明ArrayList时,如不指定容量,则默认为10;在声明LinkedList时,为空列表。
Vector:
它的用法和ArrayList几乎一样,大小可变的数组,有下标,Vector相对ArrayList来说,属于古董级别。在
JDK1.0就已经存在了。虽然它是线程安全的,但是尽量少用,效率低。
Vector的枚举器遍历:
public static void main(String[] args) {
Vector<String> csp = new Vector<String>();
csp.add("利");
csp.add("奇");
csp.add("马");
csp.add("好");
csp.add("可");
csp.add("怕");
csp.add("!");
//古老的遍历法:枚举器
Enumeration<String> elements = csp.elements();
while(elements.hasMoreElements()) {
String nextElement = elements.nextElement();
System.out.println(nextElement);
}
}
欲知后事如何,请听下回分解!