Java中的数组与集合
此文转载自:http://student-lp.iteye.com/blog/2082362
在java编程的过程中,我们不能确定某一类型的对象到底会需要多少,为了解决这个问题,java提供了容纳对象的多种方式。其中内建的类型是数组;此外还提供了“集合类”,利用这些集合类,我们就可以容纳并操作自己的对象。
一、数组
如何区分数组和其他集合类呢?其实有两种方式可以区分开:效率和类型。在java中,数组是一个简单的先行序列,它使得元素的访问速度非常快,但付出的代价是--创建一个数组对象时,他的大小是固定的,而且不可在那个数组对象的“存在时间”内发生改变(也就是只能容纳一种类型的对象)。
有关数组越界问题?在java中,无论使用的是数组还是集合,都会进行范围检查---若超过边界,就会获得一个RuntimeException错误。
数组的初始化,我们在创建一个数组后,自动进行了初始化,初始化值为null。而对应基本类型的数组,会自动初始化为零(数值类型),null(字符类型)或者FALSE(布尔类型)。
二、集合
1、早期集合类型
在早期java提供了四种类型的“集合类”:Vector(适量)、BitSet(位集)、Stack(堆栈)以及Hashtable(散列表)。在使用这些java集合时会发现一个缺点,就是:将一个对象置入一个集合时会丢失类型信息。之所以发生这种情况,是由于当初编写集合时,那个集合的程序员根本不知道用户到底想把什么类型的置入到集合中。为了解决这个问题,集合实际容纳的类型为object。这些早期类型已经不太常用,所以这里不再细讲。下面我们主要了解一下新集合。
2、新集合
1) 新的集合库考虑了“容纳自己对象”的问题,并将其分割成两个明确的概念:
①集合(Collection):一组单独的元素,通常应用了某种规则。在这里,List(列表)区分元素的顺序,且允许出现重复的值;Set(集)不区分元素的顺序,不允许出现重复的值;
②映射(Map):一系列“键--值”对。不允许有重复的键,每个键最多对应一个值。
Collection和Map可以通过多种形式实现,下面列出的是一个可以帮助大家立即的集合示意图:
总的说来,Java API中所用的集合类,都是实现了Collection接口,他的一个类继承结构如下:
Collection<--List<--Vector
Collection<--List<--ArrayList
Collection<--List<--LinkedList
Collection<--Set<--HashSet
Collection<--Set<--HashSet<--LinkedHashSet
Collection<--Set<--SortedSet<--TreeSet
2)list常用的衍生类
Vector : 基于Array的List,其实就是封装了Array所不具备的一些功能方便我们使用,它不可能不受Array的限制。性能也就不可能超越Array。所以,在可能的情况下,我们要多运用Array。另外很重要的一点就是Vector:sychronized(线程安全)的,这个也是Vector和ArrayList的唯一的区别。
ArrayList:同Vector一样是一个基于Array上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector优越一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。
LinkedList:LinkedList不同于前面两种List,它不是基于Array的,所以不受Array性能的限制。它每一个节点(Node)都包含两方面的内容:1.节点本身的数据(data);2.下一个节点的信息(nextNode)。所以当对LinkedList做添加,删除动作的时候就不用像基于Array的List一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了。这就是LinkedList的优势。
总结:1. 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对;
2. 所有的List中可以有相同的元素,例如ArrayLIst中可以有 [ tom,koo,too,koo ];
3. 所有的List中可以有null元素,例如[ tom,null,1 ];
4. 基于Array的List(Vector,ArrayList)适合查询,而LinkedList(链表)适合添加,删除操作。
3)set常用的衍生类
HashSet:HashSet的存储方式是把HashMap中的Key作为Set的对应存储项。看看HashSet的add(Object obj)方法的实现就可以一目了然了。
public boolean add(Object obj)
{
return map.put(obj, PRESENT) == null;
}
这个也是为什么在Set中不能像在List中一样有重复的项的根本原因,因为HashMap的key是不能有重复的。
LinkedHashSet:HashSet的一个子类,一个链表。
TreeSet:SortedSet的子类,它不同于HashSet的根本就是TreeSet是有序的。它是通过SortedMap来实现的。
总结:1. Set实现的基础是Map(HashMap);
2. Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象
3)list和set却别
虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在HashMap的基础上来实现的,这个就是Set和List的根本区别。
4)映射
HashTable: 实现一个映象,所有的键必须非空。为了能高效的工作,定义键的类必须实现hashcode()方法和equal()方法。这个类是前面java实现的一个继承,并且通常能在实现映象的其他类中更好的使用。并且Hashtable是同步的
HashMap: 实现一个映象,允许存储空对象,而且允许键是空(由于键必须是唯一的,当然只能有一个),即null value和null key。HashMap是非同步的。
WeakHashMap:WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
TreeMap: 实现这样一个映象,对象是按键升序排列的。
5)同步性
①Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并 不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带 来的不必要的性能开销。
②Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
6)常见的对比
①Vector和ArrayList:参见5)同步性①
②arraylist和linkedlist:ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构;对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针;对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据;
③HashMap与TreeMap:TreeMap是有序的,而HashMap是无序存储的;在Map 中插入、删除和定位元素,HashMap 的效率要更高一些;
④hashtable与hashmap:参见5)同步性②
三、Collections和Arrays类的使用
1、Collections定义了多种集合操作的方法,实现对集合元素排序,取极值,批是拷贝,集合结构转换,循环移位以及匹配检查等功能
相关方法:sort(List<T> list) 根据元素的自然顺序 对指定列表按升序进行排序。
reverse(List<?> list) 反转指定列表中元素的顺序。
shuffle(List<?> list) 使用默认随机源对指定列表进行置换。
copy(List<? super T> dest, List<? extends T> src) 将所有元素从一个列表复制到另一个列表。
list(Enumeration<T> e) 返回一个数组列表,它按返回顺序包含指定枚举返回的元素
frequency(Collection<?> c, Object o) 返回指定 collection 中等于指定对象的元素数
max(Collection<? extends T> coll) 根据指定比较器产生的顺序,返回给定 collection 的最大元素
rotate(List<?> list, int distance) 根据指定的距离轮换指定列表中的元素。
2、Arrays类定义了多种数组操作方法,实现了对数组元素 排序,填充,转换为列表或字符串形式、增强的检索和深度比较等功能
sort()对指定的 byte 型数组按数字升序进行排序
binarySearch(int[] a, int key) 使用二分搜索法来搜索指定的 int 型数组,以获得指定的值。
toString(Object[] a) 返回指定数组内容的字符串表示形式。