《Java编程思想》之对象的集合(数组、List、Set、Map)一
2012-02-03 00:19 java线程例子 阅读(272) 评论(0) 编辑 收藏 举报1、Arrays类:提供了操作数组的一些static方法,如
fill() 用于以某个值填充整个数组。
sort() 用于对数组的排序,需要参数的类型实现Comparable接口
binarySearch() 用于在已经排序的数组中查找元素。
asList() 接受任意的数组为参数,并将其转变为List容器。
……
2、如果一个字符串需要多次改变其值,那么应该使用更高效的StringBuffer取代String。
3、复制数组System.arraycopy(),用它复制数组比用for循环复制要快得多。
4、基本类型数组和对象数组都可以复制,然而,如果复制对象数组,那么只是复制了对象的引用——而不是对象本身的拷贝。这被称作“浅复制”。
5、数组的比较:
Arrays .equal()
import java.util.Arrays; public class Test{ public static void main(String[] args){ String[] s1 = new String[5]; Arrays.fill(s1,"Hi"); String[] s2 = {"Hi", "Hi", "Hi", "Hi", "Hi"}; System.out.println(Arrays.equals(s1, s2)); System.out.println(s1.equals(s2)); System.out.println(s1==s2); } }
1).对于Arrays.equals ,S1的所以元素指向同一个对象,而数组s2包含五个相互独立的对象,然而,数组相等是基于内容的(通过Object.equal()比较),所以结果为true。
2).但是后两个语句输入都是false。原因呢?
6、数组元素的比较:
1).Java有两种方式来提供比较功能。第一种是实现java.lang.Comparable接口,此接口中只有compareTo(Object o)一个方法。
2).实现Comparator接口,区中有俩个方法compare(Object o1, Object o2)和equals(Object o)两个方法。
7、Java标准库:针对基本类型设计的“快速排序(Quicksort)”,针对对象设计的“稳定归并排序”。
8、若找到目标,Arrays.binarySearch()产生的返回值等于或大于。否则,它将产生负返回值,表示若要保持数组的排序状态,此目标元素所应该插入的位置,这个负值得计算方式是:
-(插入点)- 1;
插入点是指,第一个大于查找对象的元素在数组的位置。如果数组中所有元素都小于要查找的对象吗,“插入点”就等于被查找数组的大小size()。
如果数组中包含重复的元素,则无法保证找到的是哪一个。此算法确实不是专为包含重复元素的数组而设计的,不过任然可用。
如果需要对没有重复元素的数组排序,可以使用TreeSet(保持数组顺序),或者LinkedHashSet(保持插入顺序.。
9、基本数据数组无法使用Comparator进行排序。
10、在使用binarySearch()时必须提供同样地Comparator(使用方法的重载版本)。
11、数组是效率最高的保持一组对象的方式,它是你的第一选择。而且,如果要保存基本类型,则只能用数组。
12、 Java容器类类库的用途是"保存对象",并将其划分为两个不同的概念:
1).Collection。一个独立的元素,这些元素都服从一条或多条规则。List必须保存元素特定的顺序,而Set不能有重复元素。
2).Map。一组成对的”键值对“对象。初看起来这似乎应该是一个Collection,其元素是成对的对象,但是这样的设计实现起来太笨拙了,于是我们将Map明确提取出来形成一个独立的概念。另一方面,如果使用Collection表示Map的部分内容,会便于查看此部分内容。因此Map可以返回所有键组成的Set,所有值组成的Collection,或其键值对组成的Set;并且象数组一样容易扩展成多维Map,无需增加新的概念,只要让Map中键值对的每个“值”也是一个Map即可(此Map中的“值”还可以是Map,依此类推)。
13、
1).List按对象进入的顺序保存对象,不做排序或编辑操作。
2).Set对每个对象只接受一次,并使用自己内部的排序方法(通常,你只关心某个元素是否属于Set,而不关心它的顺序--否则应该使用List)。
3).Map同样对每个元素保存一份,但这是基于"键"的,Map也有内置的排序,因而不关心元素添加的顺序。
4).如果添加元素的顺序对你很重要,应该使用 LinkedHashSet或者LinkedHashMap.、
14、Collections中的fill()方法也是只复制同一个对象的引用来填充整个容器,并且只对List对象有用。
15、容器的缺点:将对象加入容器的时候就丢失了类型信息。容器只保存对Object的引用,Object是所有类的基类,因此容器可以保存任何类型的对象。(当然不包括基本类型,因为它们不是真正的对象,没有继承任何东西。)
16、如果原本是使用ArrayList,但是后来考虑到容器的特点,该用Set,那该怎么做?或者你打算写通用的代码,它们只是使用容器,不知道或者说不关心容器的类型,那么如何才能不重写代码就可以应用与不同类型的容器?
迭代器(也是一种设计模式)的概念可以用于达成次目的。迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构(也就是不同容器的类型)。此外,迭代器通常被称为"轻量级"对象:创建它的代价小。
17、Collection中并不包括随机访问所选择元素的get()方法。因为Collection包括Set,而Set是自己维护内部顺序的(这使得随机访问变得没意义)。因此,如果你想要检查Collection中的元素,必须使用迭代器。
18、Java中,Vector、Stack和Hashtable已经过时。
19、List的功能方法
如果再开发环境中,性能开销主要由其他因素产生,那么ArrayList与LinkedList之间的开销差异就不重要了,无论使用哪一种都可以。
20、Set的功能方法:
Set具有与Collection完全一样得接口,因此没有任何额外的功能。实际上Set就是Collection,只是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set不保存重复的元素。
import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import java.util.TreeSet; public class TestSet{ static void fill(Set<Object> s){ //split根据匹配给定的正则表达式来拆分此字符串。 s.addAll(Arrays.asList("one two three four five six seven".split(" "))); } public static void text(Set<Object> s){ //replaceAll(String regex,String replacement) //使用给定的 replacement替换此字符串所有匹配给定的正则表达式的子字符串。 System.out.println(s.getClass().getName().replaceAll("\\w+\\.", "")); //调用多次:为了验证Set不保存重复的元素。 fill(s); fill(s); fill(s); System.out.println(s); s.addAll(s); s.add("one"); s.add("one"); s.add("one"); System.out.println(s); System.out.println("s.contains(\"one\"):" + s.contains("one")); } public static void main(String[] args){ text(new HashSet<Object>()); text(new TreeSet<Object>()); text(new LinkedHashSet<Object>()); } }
运行结果:
从运行结果可以注意到,HashSet所维护的元素的次序不同于TreeSet和LinkedHashSet,因为它们保存元素以便以后还能找到该元素的方式个不相同。
1).TreeSet采用红黑树的数据结构排序元素。
2).HashSet则采用散列函数,这是专门为快速查询二设计的。
3).LinedHashSet内部使用散列加快查询速度,同时使用链表维护元素的次序。
20、使用HashSet和TreeSet这两种情况下,都必须为类定义equals();而hashCode(),只有在类被HashSet用到的时候才是必要的(这种可能性很大,因为HashSet通常是使用Set的第一选择)。无论如何,作为一种编程风格,当覆盖equals()的时候,就应该同时覆盖hashCode()。
21、Map的功能方法:
“键(key)“必须是唯一的,而”值(value)“可以有重复。
import java.util.HashMap; import java.util.Map; import java.util.Random; class Counter{ int i = 1; public String toString(){ return Integer.toString(i); } } public class Statistics{ private static Random rand = new Random(); public static void main(String[] args){ Map<Object, Object> m = new HashMap<Object, Object>(); for(int i = 0; i < 10000; i++){ Integer r = new Integer(rand.nextInt(20)); if(m.containsKey(r)){ ((Counter)m.get(r)).i++; } else{ m.put(r, new Counter()); } } System.out.println(m); } }
这里为什么不之间用Integer而是另外写一个Counter类呢?
原因:Java包装器类(如这里的Integer)的对象一旦创建,就无法改变它的值。
下接:
《Java编程思想》之对象的集合(数组、List、Set、Map)二
以上内容整理自《Java编程思想》,若有遗漏,请您不吝指出!