可以看看这两篇博文
http://www.cnblogs.com/mingcn/archive/2010/10/22/JavaContainer.html
http://michaelfly.iteye.com/blog/519484
1.集合类的由来
对象用来封装各种不同的数据,比如person类里装了 string类型的name,int型的age
但是对象多了咋办,就用集合类来装,person1、person2.。。
2.集合的特点
集合容器只能用来存储对象,注意与数组的区别,数组也可以存储对象,但是数组还能存储基本数据类型。
集合的长度是可变的,随便你加减操作。而数组是一定的
3.不同集合的共性
不同集合容器内部的数据结构不同,所以有所区别,但是他们肯定有共性
往上抽取,就形成一些共性的框架
最基本的就是collection接口,里面有各种添加删除判断获取等方法
注意迭代器,iterator,取出集合里的元素,返回的是一个迭代器对象,用来取出集合里的对象
4.常用集合类容器,比如arraylist,collection的实现类
打印这个arraylist的时候,会打印出其中的所有元素
removeall移除相同的元素,retainall 保留相同的元素
迭代器的使用
hasnext,当还有元素可取时,返回true
next(),下一个元素
public class Hello {
public static void main(String[] args){
Collection col = new ArrayList();
col.add("abc1");
col.add("abc2");
col.add("abc3");
Iterator it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
abc1
abc2
abc3
优化:这里循环结束了,iteratr还在,next()这个指向下一个的指针还在,占了一点内存,可以利用for循环来写,循环结束就销毁了,这种写法更常见
public static void main(String[] args){
Collection col = new ArrayList();
col.add("abc1");
col.add("abc2");
col.add("abc3");
for(Iterator it = col.iterator();it.hasNext();){
System.out.println(it.next());
}
最常用的两个子接口:list和set
list是有序的-存入和取出的顺序是相同的,list有索引,list允许重复
set是hashmap的变种。为了让单列集合元素唯一,不允许重复
关于list的取出方式,除了collection通用的方式(set只有这个),还可以通过遍历位置信息去
demo:给list某个元素后加一个元素,如果list里没有这个元素,则输出整个list
public class Hello {
public static void main(String[] args){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
Iterator it = list.iterator();
while(it.hasNext()){
//add加的是对象,这里返回的应该也是对象
//开始读取
Object obj = it.next();
if(obj.equals("abc2")){
list.add("abc5");
}else {
System.out.println("next:"+obj);
}
}
System.out.println(list);
}
}
这个时候会报错,打印了第一个元素,然后挂了
为啥呢,因为往list里添加了元素,而iterator不知道
这里不能直接通过list添加,而可以通过列表迭代器来,只有list有一个单独的迭代器
public class Hello {
public static void main(String[] args){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
//不能在迭代器内用list来操作元素
ListIterator it = list.listIterator();
while(it.hasNext()){
//add加的是对象,这里返回的应该也是对象
//开始读取
Object obj = it.next();
if(obj.equals("abc3")){
//通过listIterator来迭代
it.add("abc6");
}else {
System.out.println("next:"+obj);
}
}
System.out.println(list);
}
}
5.list常用对象 arraylist,linkedlist,vector
vector出现的最早,内部是一个数组,但是可变大小,同步的,创建一个数组,将原来的东西复制进来,100%延长,增删查询都慢
arraylist用来代替vector,内部也是数组,可变大小,不同步的,他是在原有数组上延长,是50%的延长,更省事,关于不同步,上面的例子就很好的说明了,查询快
linkedlist,内部是链表,非同步的,增删元素比较快
6.MAP 和collection是一个级别的接口
但他是键值对,和collection最大的区别
put方法,返回的是之前key对应的value值,第一次存返回的就是null,或者说之前没有值,就是空
常用的实现类 hashmap
Map<Integer, String> map = new HashMap<Integer, String>();
想要取值,可以先找到所有key
6.1 通过getSet获得所有key的set集合,再通过set的迭代器获取每一个键,再通过键获取value
Map<Integer, String> map = new HashMap<Integer, String>();
//获得所有键的set集合
Set<Integer> keyset = map.keySet();
//通过set集合获得迭代器
Iterator<Integer> its = keyset.iterator();
while(its.hasNext()){
//通过迭代器取键
Integer key = its.next();
//通过键取值
String value = map.get(key);
System.out.println(key+":"+value);
}
6.2 entrySet 返回的是键值关系的set集合,通过把map转成Set,就能拿到一个迭代器,entrySet将映射关系作为对象存储到集合中,而这个映射关系类型是map.entry型
Map<Integer, String> map = new HashMap<Integer, String>();
Set<Map.Entry<Integer, String>> entryset = map.entrySet();
Iterator<Map.Entry<Integer, String>> itss = entryset.iterator();
while(itss.hasNext()){
Map.Entry<Integer, String> me = itss.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+" : "+value);
}
map.entry是一个静态的内部接口,会随着map的加载而加载,entry是映射关系的对象,访问map里的键和值,封装在map内
6.3 values()
返回所有值的collection对象,键唯一,值不唯一
Map<Integer, String> map = new HashMap<Integer, String>();
Collection<String> values = map.values();
Iterator<String> itsss = values.iterator();
while(itsss.hasNext()){
System.out.println(itsss.next());
}
6.4 map的子类
hashtable:内部结构是哈希表,非空,类似于collection中的vector,最早一个,同步的
hashmap:内部是哈希表,允许null作为键值,不是同步的(collection里的set是由hashmap实现的,就是他的一个实例,不过为了保证单列集合的元素唯一性才有的set)
treemap:内部结构是二叉树,不同步,可以对map里的键进行排序
hashtable有一个子类,properties,很生猛,属性集,用来存储键值对型的配置文件,常见与IO结合使用
7.泛型
是一种安全机制,在容器集合里面很常见
对于一些类型不匹配而导致的运行时错误转到编译来发现,也无需强转类型了
当数据类型不是很确定的时候,就加上<>成为泛型,将需要的数据类型传入,其实就是一个参数范围,类似于方法里的形参
只要有带<>的类或者接口,就需要明确类型
运行时,泛型会被去掉,生成的class文件里不带泛型,此即泛型的擦除,为了去兼容运行时的类加载器
由于只在编译时会带上泛型,那么在运行过程中,这些对象都还是object类,这样在实际操作时,本来应该还需要强转,但是强转是由一定隐患的,所以有了补偿机制
,通过在运行时获取类型来强转
以treeset为例
public class Person {
String name;
int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class MyGenericDemo {
public static void main(String[] args) {
TreeSet<Person> ts = new TreeSet<Person>();
ts.add(new Person("lisi",20));
ts.add(new Person("wangwu",30));
ts.add(new Person("yamiedie",18));
ts.add(new Person("qinshou",60));
Iterator<Person> it = ts.iterator();
while(it.hasNext()){
Person p = it.next();
System.out.println(p);
}
}
}
跑起来,挂了,为嘛子,因为treeset是二叉树结构的,需要比较,他有比较器的方法,compare和equal
Exception in thread "main" java.lang.ClassCastException: com.leo.bean.Person cannot be cast to java.lang.Comparable
应该在person类实现一个接口,compare,任何可比较的方法里都有这个接口
先按年龄排序,相等时按名字排序
这里用到了compareTo方法,他是按照第一个字符的ASC码比较,返回差值
public class Person implements Comparable<Person>{
String name;
int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Person p) {
// TODO Auto-generated method stub
int temp = this.age-p.age;
return temp == 0?this.name.compareTo(p.name):temp;
}
}
while(it.hasNext()){
Person p = it.next();
System.out.println(p);
System.out.println(p.toString());
System.out.println(p.getName()+":"+p.getAge());
}
<pre name="code" class="plain">com.leo.bean.Person@659e0bfd
com.leo.bean.Person@659e0bfd
yamiedie:18
com.leo.bean.Person@2a139a55
com.leo.bean.Person@2a139a55
lisi:20
com.leo.bean.Person@15db9742
com.leo.bean.Person@15db9742
wangwu:30
com.leo.bean.Person@6d06d69c
com.leo.bean.Person@6d06d69c
qinshou:60
另一种比较的方法,equals(object o) 参数不能改类型的
通配符 ?
? extends 000 类型范围限制,表明只能接收000及他的子类
如何选择 集合容器
唯一?
需要 set
顺序?
需要 treeset
不需要 hashset
和存储一致:linkedhashset
不需要 list
需要频繁增删?
需要 linkedlist
不需要 arraylist