集合类和泛型
一、集合类
集合类和数组同是容器,有何不同?
1.数组的长度是固定的,集合类的长度不固定
2.数组存储基本类型,集合类存储对象,集合中不能存基本数据类型。
集合容器因为内部数据结构不同,有多种具体容器。
不断向上抽取,就形成了集合框架。
框架的顶层为Collection接口。
(一)LIst
有序的Collection,此处有序是指数据存入的顺序。
特点:
1.有序,存入和取出的顺序一致
2.所有元素有角标(素引)
LIst常见的特有方法有一个共同的特点,就是可以操作角标。
List list=new ArrayList(); list.add("a1"); list.add("a2"); Iterator it=list.Iterator(); while(it.hasNext()) { Object obj=it.Next(); if (obj.equals("a2")) { list.add("a3"); } }
上述代码在执行时是错误的,因为List类的迭代器在使用时容器长度是固定的,不能在迭代时修改容器的长度。
要修改上述错误,我们不能在迭代时修改容器的长度,但是我们可以修改迭代器的长度。可以使用Iterator接口的子接口ListIterator来实现。代码如下:
List list=new ArrayList(); list.add("a1"); list.add("a2"); Iterator it=list.listIterator(); //使用列表迭代器 while(it.hasNext()) { Object obj=it.Next(); if (obj.equals("a2")) { it.add("a3"); //使用迭代器的插入方法 } }
List接口的有三种:(一般除了Vector外,都是不同步的。)
1.Vector:内部结构是数组数据结构,容量会自动调整。Vector是同步的。
2.ArrayList:内部也是数组数据结构,基本等同于Vector,但是它是不同步的,单线程中效率较高。查询的速度快。
3.LinkedList:内部是链表数据结构,是不同步的,增删速度非常快。
(二)Set
特点:
1.所有元素不重复
2.没有顺序
主要有两种结构:
1.HashSet:无重复,无顺序
判断两个对象是否相同,先判断两个对象的HashCode,如相同,再判断equals,如相同,则两个对象相同。如HashCode不相同,则无须再判断equals。
2.TreeSet:无重复,有顺序
(三)Map
Collection一次添加一个元素,Map一次添加一对元素。所以Map也叫双列集合,Map集合中存储的是键值对。一个映射中不能包含重复的键,每个键只能对应一个值。也就是说Map必须保证键的唯一性。
1.Map添加:
value put(key,value):返回前一个和key关联的值,如果没有,返回null
2.删除
void clear():清空map集合
value remove(key):根据指定的key翻出对应的键值对
3.判断
boolean containsKey(key);
boolean containsValue(value);
boolean isEmpty();
4.获取
value get(key):通过键获取值,如果没有该键,返回null。当然可以通过返回null,来判断是否包含指定键。
int size(); 获取键值对的个数
Map集合没有迭代器。通过Map转成set就可以迭代。找到了另一个方法entrySet。该方法将键和值的映射关系作为对象存储到了set集合中,而这个映射关系的类型就是Map.Entry类型。
Set<Map.Entry<Integer,String>> entrySet=map.entrySet(); Iterator<Map.Entry<Integer,String>> it=entrySet.iterator(); while (it.hasNext()) { Map.Entry<Integer,String> me=it.next(); Integer key=me.getKey(); String value=me.getValue(); System.out.println(key+":"+value); }
Map常用的子类:
1.Hasthtable:内部结构是哈希表,是同步的,不允许null作为键和null作为值
有一个子类:properties,用来存储键值对型的配置文件的信息。经常和IO技术相结合。
2.HashMap:内部结构是哈希表,是不同步的,允许null作为键和null作为值
3.TreeMap:内部结构是二叉树,是不同步的,可以对Map集合中的键进行排序。
二、泛型
在JDK1.5以后出现。
好处:
1.将运行时期的问题ClassCastException转到了编译时期。
2.避免了强制转换的麻烦。
<>:什么时候用?当操作的引用数据类型不确定的时候,就使用<>。将要操作的引用数据类型引入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。
定义一个泛型类:
pulbic class Tool<w>
{
……
}
也可以定义一个泛型接口
interface Inter<T>
{
public void show(T t)
{ }
}
可以将泛型定义在方法上:
public <w> void show(w str)
{
……
}
当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上。
public static <w> void show(w str)
{
……
}
在使用泛型参数时,如果有多种泛型,可使用如下代码:
public void show(Tool<?> t)
{
Iterator <?> it=t.iterator();
……
}
或用如下代码:
public <T> void show(Tool<T> t)
{
Iterator <T> it=t.iterator();
……
}
泛型通配符还可以进行限定,如向上限定(一般用于存储数据):
public static void show(Tool<? extends Person> str)
{
……
}
也可向下限定(一般用于读取数据):
public static void show(Tool<? super Person> str)
{
……
}
最后,集合的一些技巧:
需要唯一吗?
需要:Set
需要制定顺序:
需要:TreeSet
不需要:HashSet
不需要:List
需要频繁增删吗?
需要:LinkedList
不需要:ArrayList
Array——数组、查询快、有角标
Link——链表、增删快、add/get/remove/first/lash等方法
Hash——哈希表、唯一性,有时需要覆盖hashCode和equals方法
Tree——二叉树、排序,两个接口:Comparable和Comparator
三、集合工具
1. Collections
里面的方法都是静态的。比如排序:
public static void show() { List<String> list=new ArrayList<String>(); list.add("abcde"); list.add("cba"); list.add("aa"); list.add("zzz"); Collections.sort(list); System.out.println(list); }
比如交换值:
Collections.swap(list,i,j);
对集合中的位置进行随机
Collections.shuffle(list);
给非同步的集合加锁,可以使用Collections.synchronizedCollection(Collection<T> c),其原理如下 :
List list=new ArrayList(); //非同步 list=MyCollections.synList(list); //返回一个同步的list class MyCollections { public List synList(List list) { return new MyList(list); } private class MyList implements List { private List list; private static final Object lock=new Object(); MyList(List list) { this.list=list; } public boolean add(Object obj) { synchronized(lock) { return list.add(obj); } } public boolean remove(Object obj) { synchronized(lock) { return list.remove(obj); } } } }
2.Arrays
将数组转成集合
int [] arr={31,11,51,61};
List<int []> list=Arrays.asList(arr);
将集合转数组
List <String> list=new ArrayList<String>(); list.add("abc1"); list.add("abc2"); list.add("abc3"); /*toArray需要传定一个指定类型的数组,如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同的size的数组,如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位默认为null */ string[] arr=list.toArray(new String[2]); System.out.println(Arrays.toString(arr));
注意,导入静态名称空间时,要用
import static java.util.Collections.sort;