您的位置:首页 > 职场人生

黑马程序员——学习笔记08.Java集合

2014-01-04 12:39 176 查看
----------------------ASP.Net+Android+IOS开发.Net培训、期待与您交流!
----------------------

集合的基本概念

1.java是面向对象的设计开发编程语言,所操作的元素都是以对象为单位的。集合就是存在对象的容器,集合是存储对象最常用的一种方式。集合中可以存储任意类型的对象,而且长度可变。在程序中有可能无法预先知道需要多少个对象,那么用数组来装对象的话,长度不好定义,而集合解决了这样的问题。

2.与数组的异同:数组和集合类都是容器;数组长度是固定的,集合长度是可变的;数组和结合都可以存储基本数据类型和对象,数组在定义的时候就需要指定存储的数据类型,而集合可以不用。

3.集合的作用:是用来存储对象数据的,也是用来操作数据的,例如:增、删、查、改等功能

集合常用的基本体系

---|Collection: 单列集合

---|List: 有存储顺序,可重复

---|ArrayList: 底层由数组实现,查找快,增删慢

---|LinkedList: 底层由链表实现,增删快,查找慢

---|Vector:和ArrayList原理相同,但线程安全,效率略低。

---------------------------------------------------------------------

---|Set: 无存储顺序, 不可重复

---|HashSet:底层是按照哈希表数据来存储对象元素,底层实现

实际上是一个HashMap实例,

---|LinkedHashSet;是由哈希表和链表双重实现的。存储是

按照先后顺序排列的,在HashSet基础上有所改进。

---|TreeSet:底层是按照二叉树原理来存储数据的。存储元素

要实现Comparable接口或者自定义一个比较器。

--------------------------------------------------------------------

---| Map: 双列集合(键值对)

---|HashMap:实现原理与HashSet相同

---|LinkedHashMap:实现原理与LinkedHashSet相同。

---|TreeMap:实现原理与TreeSet相同

---|Hashtable: 线程安全的。

---|Properties:永久性的属性集,键值对是按字符串形式存在的

List集合:有存储顺序, 可重复,可存储null元素

1.ArrayList

实现原理:数组实现。因为数组的内存空间地址是连续的.ArrayList底层维护了一个Object[]用于存储对象,默认数组的长度是10。可以通过 new ArrayList(int size)显式的指定用于存储对象的数组的长度。当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。

优点:查找快。数组是可以直接按索引查找, 所以查找时较快

缺点:增删慢。由于ArrayList是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。

假设向数组的0角标位置添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要要将老数组的内容拷贝到新数组中.所以数组的增删的效率是很低的.

2.LinkedList

实现原理:链表实现,增删快,查找慢。由于链表结构的数据在内存中的地址不连续,所以每个元素中保存的有下一个元素的索引值。

优点:增删快。增加时只需要让前一个元素记住新元素的索引,让新元素记住下一个元素就可以了。删除时让这个元素的后一个元素记住这个元素的前一个元素即可. 这样的增删效率较高。

缺点:查找慢。查询元素时需要一个一个的遍历, 所以效率较低。虽然元素有对应的索引,但是查找的时候,需要从头往下找,显然是没有数组查找快的

3.Vector

实现原理和ArrayList相同,区别就是它是线程安全的,当多个线程对集合中的数据进行操作时建议使用此集合,但效率会降低。单线程使用ArrayList较为常见。

在实际开发中使用ArrayList频率较高。

Set集合:无存储顺序, 不可重复

1.HashSet

实现原理:哈希表实现。实际是通过HashMap来实现功能的。创建HashSet对象时,底层是创建了一个HashMap对象来完成其功能的。

实现特点: HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同)而 是按照哈希值来存储的,所以调用和删除数据也是按照哈希值取得。

HashSet不存入重复元素的规则:调用存入元素的hashcode()方法和equals()方法。那是如何具体实现的呢?当你试图把对象加入HashSet时,HashSet会使用对象的hashCode()计算出存入对象的哈希值来判断对象存入的哈希位置,同时也会与其他已经加入的对象的hashCode进行比较,如果没有相等的哈希值,HashSet就会认为对象没有重复出现。所以如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。如果存入元素(对象)的hashCode值相同,是不是就无法存入HashSet中了吗?当然不是,会继续使用equals进行比较.如果调用equals返回true 那么HashSet认为新加入的对象重复了所以加入失败.如果equals()方法返回false那么HashSet 认为新加入的对象没有重复,新元素可以存入集合中。

因此我们自定义类的时候通常需要重写hashCode()和equals()方法,以确保当用HashSet集合来存入元素时,没有存入相同元素,造成资源浪费。当要删除一个集合中元素时,会根据指定元素的hashCode值来查找对应元素,如果找到有对应的元素的hashCode相同,那么就放回true,删除成功。如果没有,则返回false。

总结:

元素的哈希值是通过元素的hashcode方法来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls方法返回结果为true,HashSet就视为同一个元素,存入失败。如果equals方法返回结果为false,就不是同一个元素,可以存入这个元素。所有自定义一个类时,覆写了hashCode方法就一定要覆写equals方法。

注意:

如果一个对象成功添加到了HashSet中,那么最好不要修改这个对象中参与到hashcode方法中的属性值。因为一旦修改了,这个对象的hashCode值发生改变了,在修改后的这个对象的hashCode对应的哈希表位置中并没有这个对象,再去删除这个元素的时候就无法删除成功,易造成内存泄露。HashSet集合中元素是无序的。它不保证集合的迭代顺序,特别是它不保证该顺序恒久不变.

此类允许使用 null 元素。

2.TreeSet

实现原理:二叉树的数据结构,默认对元素进行自然排序,如果使用comparaTo或者compara方法在比较两个对象,返回值为0,那么元素重复,元素添加失败。

实现特点:TreeSet可以自然排序,那么TreeSet也可以按指定规则对元素进行排序。TreeSet是怎样进行存储元素的呢?怎样进行排序的呢?TreeSet在存储元素时,存储元素(对象)必须具备比较性(实现Comparable接口覆写comparaTo(Object obj)方法)或者按照指定按照指定比较规则(自定义比较器)进行对象的比较来进行排序。当元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,这种方式叫做元素的自然排序也叫做默认排序。当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备比较规则.需要定义一个类实现接口Comparator,重写compare(Object o1,Object o2)方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。

注意:

当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;在重写compareTo或者compare方法时,必须要明确比较的主要条件相等的情况下要比较次要条件。假设姓名和年龄一致的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接比较放回0,因为两个人姓名不同年龄相同是两个不同的人。此时就需要进行次要条件判断,当年龄相同需要判断姓名,只有姓名和年龄同时相等时才可以返回0。这样可以避免遗漏要存入的不同数据。

此类不允许使用null元素。

3.LinkedHashSet

实现原理:使用链表和哈希表双重结合进行存储元素。元素的顺序是按照存储添加的顺序进行排列的。但需要对一组数据进行存储,并且去除重复元素,按照存入时的顺序,可以

用LinkedHashSet。此类允许使用null元素。

Map集合:双列集合,是以键值对形式存在的。键要求不能重复,值可以重复。

1.HashMap

实现原理:通过哈希表来实现Map接口的。

实现特点:线程不同步的,不安全。允许存入null键和null值。存入元素必须要覆写hashCode()和equals()方法。

2.LinkedHashMap

实现原理:通过哈希表和链接列表双重实现Map接口的。

实现特点:具有可预知的迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。是继承HashMap的。

3.TreeMap

实现原理:通过二叉树原理来实现Map接口的。

实现特点:可对Map集合中的键进行排序,但存入的元素必须要实现Comparable接口或自定义比较器实现Comparator接口。不允许存入null键和null值。

4.Hashtable

实现原理:通过哈希表来实现Map接口的。

实现特点:线程是同步的,安全的。不允许存入null键和null值。效率较低。

5.Properties

实现原理:是继承Hashtable,它表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

实现特点:因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。如果在“不安全”的 Properties 对象(即包含非 String 的键或值)上调用store或save方法,则该调用将失败。类似地,如果在“不安全”的Properties 对象(即包含非 String 的键)上调用 propertyNames或list方法,则该调用将失败。

Iterable接口:Collection的父接口,实现了Iterable的类就是可迭代的,并且支持增强for循环。该接口只有一个方法即获取迭代器的方法iterator(),可以获取每个容器自身的迭代器Iterator。Collection接口进程了Iterable接口,该接口只有一抽象方法iterator(),返回迭代器Iterator。所有Collection体系中的集合都具备获取自身迭代器的方法,因为数据结构不同,每个子类集合都进行了重写。在进行迭代器遍历元素时,不能通过集合对元素进行操作。如果操作,那么迭代失败。

Iterator迭代器接口:List有一个特有迭代器ListIterator,增添逆序进行迭代和增加设置元素的方法。

Collections:集合工具类,包含了对集合进行排序,查找等功能。

综合练习:字符串”abadcd-0o*7ffbaeba”中包含几种英文字符,每种英文字符出现了多少次,按次数排序并输出。例如:c : 1,e : 1,d : 2,f : 2,b : 3,a : 4

//定义一个方法具备将指定的字符串中字符输出英文字符次数排序。
public static void listString1(String str) {
char [] arr =str.toCharArray();
//使用TreeMap集合,key的顺序是按照元素的自然顺序排列的
TreeMap<Character,Integer> treeMap= new TreeMap<Character,Integer>();
for (int i = 0; i <arr.length ; i++) {
//只要求存储英文字符。
if(arr[i]>='a'&&arr[i]<='z'||arr[i]>='A'&&arr[i]<='Z'){
if(!treeMap.containsKey(arr[i])){
treeMap.put(arr[i], 1);
}else{
treeMap.put(arr[i],treeMap.get(arr[i])+1);
}
}
}
System.out.println("一共有"+treeMap.size()+"中英文字符");
Set<Map.Entry<Character,Integer>> st = treeMap.entrySet();
Iterator<Map.Entry<Character, Integer>> it = st.iterator();
//创建List集合,存储Map.Entry元素,存储的是每个键值对值。
ArrayList<Map.Entry<Character,Integer>> list= new ArrayList<Map.Entry<Character,Integer>>();
while (it.hasNext()) {
Map.Entry<Character, Integer> en = it.next();
list.add(en);
}
/*进行排序,按照Map.Entry的值大小来排序,使用Collections的排序功能,按照指定比较器来比较排序。*/
Collections.sort(list, new Comparator<Map.Entry<Character, Integer>>() {
@Override
public int compare(Map.Entry<Character, Integer> o1,
Map.Entry<Character, Integer> o2) {
// TODO Auto-generated method stub
return o1.getValue()-o2.getValue();
}
});
//遍历list集合
for (Entry<Character, Integer>  entry : list){
System.out.print(entry.getKey()+":"+entry.getValue()+"\t");
}

}

----------------------ASP.Net+Android+IOS开发.Net培训、期待与您交流!
----------------------

详细请查看:http://edu.csdn.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: