一起学 Java(三) 集合框架、数据结构、泛型
一、Java 集合框架
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
- 接口:是代表集合的抽象数据类型。接口允许集合独立操纵其代表的细节。在面向对象的语言,接口通常形成一个层次。
- 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构。
- 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
集合接口
序号 | name | 接口描述 |
---|---|---|
1 | Collection |
Collection 是最基本的集合接口,一个 Collection 代表一组 Object,Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。 |
2 | List |
List接口是一个有序的Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的小标)来访问List中的元素,而且允许有相同的元素。 |
3 | Set |
Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。 |
4 | SortedSet | 继承于Set保存有序的集合。 |
5 | Map | 将唯一的键映射到值。 |
6 | Map.Entry | 描述在一个Map中的一个元素(键/值对)。是一个Map的内部类。 |
7 | SortedMap | 继承于Map,使Key保持在升序排列。 |
8 | Enumeration | 这是一个传统的接口和定义的方法,通过它可以枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代。 |
集合实现类(集合类)
Java提供了一套实现了Collection接口的标准集合类。其中一些是具体类,这些类可以直接拿来使用,而另外一些是抽象类,提供了接口的部分实现。
标准集合类汇总于下表:
序号 | name | 类描述 |
---|---|---|
1 | AbstractCollection | 实现了大部分的集合接口。 |
2 | AbstractList | 继承于AbstractCollection 并且实现了大部分List接口。 |
3 | AbstractSequentialList | 继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问。 |
4 | LinkedList |
该类实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List。例如: Listlist=Collections.synchronizedList(newLinkedList(...)); LinkedList 查找效率低。 |
5 | ArrayList |
该类也是实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的情况下不要使用。ArrayList 增长当前长度的50%,插入删除效率低。 |
6 | AbstractSet | 继承于AbstractCollection 并且实现了大部分Set接口。 |
7 | HashSet |
该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。 |
8 | LinkedHashSet | 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。 |
9 | TreeSet |
该类实现了Set接口,可以实现排序等功能。 |
10 | AbstractMap | 实现了大部分的Map接口。 |
11 | HashMap | HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。 该类实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。 |
12 | TreeMap | 继承了AbstractMap,并且使用一颗树。 |
13 | WeakHashMap | 继承AbstractMap类,使用弱密钥的哈希表。 |
14 | LinkedHashMap | 继承于HashMap,使用元素的自然顺序对元素进行排序. |
15 | IdentityHashMap | 继承AbstractMap类,比较文档时使用引用相等。 |
在前面的教程中已经讨论通过java.util包中定义的类,如下所示:
序号 | name | 类描述 |
---|---|---|
1 | Vector |
该类和ArrayList非常相似,但是该类是同步的,可以用在多线程的情况,该类允许设置默认的增长长度,默认扩容方式为原来的2倍。 |
2 | Stack | 栈是Vector的一个子类,它实现了一个标准的后进先出的栈。 |
3 | Dictionary | Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。 |
4 | Hashtable | Hashtable 是 Dictionary(字典) 类的子类,位于 java.util 包中。 |
5 | Properties | Properties 继承于 Hashtable,表示一个持久的属性集,属性列表中每个键及其对应值都是一个字符串。 |
6 | BitSet | 一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。 |
import java.util.Iterator;<br/> import java.util.List;<br/> import java.util.ArrayList; public class myArrayList {<br/> public static void main(String[] args){<br/> List<String> list = new ArrayList<String>();<br/> list.add("nick");<br/> list.add("jenny");<br/> list.add("Maria"); //第一种遍历方法使用foreach遍历List<br/> for (String str : list){<br/> System.out.println(str);<br/> } //第二种遍历,把链表变为数组相关的内容进行遍历<br/> String[] strArray = new String[list.size()];<br/> list.toArray(strArray);<br/> for (int i=0;i<strArray.length;i++){<br/> System.out.println(strArray[i]);<br/> } //第三种遍历 使用迭代器进行相关遍历<br/> Iterator<String> ite=list.iterator();<br/> while (ite.hasNext()){<br/> System.out.println(ite.next());<br/> }<br/> }<br/> }
myArrayList.java
package three; import java.util.HashMap;<br/> import java.util.Iterator;<br/> import java.util.Map; public class mymap {<br/> public static void main(String[] args){<br/> Map<String, String> map = new HashMap<String, String>();<br/> map.put("name", "nick");<br/> map.put("age", "18");<br/> map.put("single", "singleDog"); //第一种:普遍使用,二次取值<br/> for (String key : map.keySet()){<br/> System.out.println(key + " " + map.get(key));<br/> } //通过Map.entrySet使用iterator遍历key和value<br/> Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();<br/> while (it.hasNext()) {<br/> Map.Entry<String, String> entry = it.next();<br/> System.out.println(entry.getKey() + " " + entry.getValue());<br/> } //第三种:推荐,尤其是容量大时<br/> for (Map.Entry<String, String> entry : map.entrySet()){<br/> System.out.println(entry.getKey() + " " + entry.getValue());<br/> } //通过Map.values()遍历所有的value,但不能遍历key<br/> for (String v : map.values()){<br/> System.out.println(v);<br/> }<br/> }<br/> }
mymap.java
二、Java数据结构
在Java中的数据结构主要包括以下几种接口和类:
- 枚举(Enumeration)
- 位集合(BitSet)
- 向量(Vector)
- 栈(Stack)
- 字典(Dictionary)
- 哈希表(Hashtable)
- 属性(Properties)
枚举(Enumeration)
Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素。
这种传统接口已被迭代器取代,虽然Enumeration 还未被遗弃,但在现代代码中已经被很少使用了。尽管如此,它还是使用在诸如Vector和Properties这些传统类所定义的方法中,除此之外,还用在一些API类,并且在应用程序中也广泛被使用。 下表总结了一些Enumeration声明的方法:
序号 | 方法描述 |
---|---|
1 | boolean hasMoreElements( ) 测试此枚举是否包含更多的元素。 |
2 | Object nextElement( ) 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。 |
package three; import java.util.Vector;<br/> import java.util.Enumeration; public class myEnumeration {<br/> public static void main(String[] args){<br/> Enumeration days;<br/> Vector dayNames = new Vector();<br/> dayNames.add("Sunday");<br/> dayNames.add("Monday");<br/> dayNames.add("Tuesday");<br/> dayNames.add("Wednesday");<br/> dayNames.add("Thursday");<br/> dayNames.add("Friday");<br/> dayNames.add("Saturday");<br/> days = dayNames.elements();<br/> while (days.hasMoreElements()){<br/> System.out.println(days.nextElement());<br/> }<br/> }<br/> }
practice
位集合(BitSet)
位集合类实现了一组可以单独设置和清除的位或标志。
该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一”位”,然后对位进行适当的设置或清除,就可以对布尔值进行操作了。
一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。这和位向量(vector of bits)比较类似。
这是一个传统的类,但它在Java 2中被完全重新设计。
BitSet定义了两个构造方法。
BitSet() //第一个构造方法创建一个默认的对象<br/> BitSet(int size) //第二个方法允许用户指定初始大小。所有位初始化为0。
BitSet中实现了Cloneable接口中定义的方法如下表所列:
序号 | 方法描述 |
---|---|
1 | void and(BitSet bitSet) 对此目标位 set 和参数位 set 执行逻辑与操作。 |
2 | void andNot(BitSet bitSet) 清除此 BitSet 中所有的位,其相应的位在指定的 BitSet 中已设置。 |
3 | int cardinality( ) 返回此 BitSet 中设置为 true 的位数。 |
4 | void clear( ) 将此 BitSet 中的所有位设置为 false。 |
5 | void clear(int index) 将索引指定处的位设置为 false。 |
6 | void clear(int startIndex, int endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 false。 |
7 | Object clone( ) 复制此 BitSet,生成一个与之相等的新 BitSet。 |
8 | boolean equals(Object bitSet) 将此对象与指定的对象进行比较。 |
9 | void flip(int index) 将指定索引处的位设置为其当前值的补码。 |
10 | void flip(int startIndex, int endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的每个位设置为其当前值的补码。 |
11 | boolean get(int index) 返回指定索引处的位值。 |
12 | BitSet get(int startIndex, int endIndex) 返回一个新的 BitSet,它由此 BitSet 中从 fromIndex(包括)到 toIndex(不包括)范围内的位组成。 |
13 | int hashCode( ) 返回此位 set 的哈希码值。 |
14 | boolean intersects(BitSet bitSet) 如果指定的 BitSet 中有设置为 true 的位,并且在此 BitSet 中也将其设置为 true,则返回 ture。 |
15 | boolean isEmpty( ) 如果此 BitSet 中没有包含任何设置为 true 的位,则返回 ture。 |
16 | int length( ) 返回此 BitSet 的”逻辑大小”:BitSet 中最高设置位的索引加 1。 |
17 | int nextClearBit(int startIndex) 返回第一个设置为 false 的位的索引,这发生在指定的起始索引或之后的索引上。 |
18 | int nextSetBit(int startIndex) 返回第一个设置为 true 的位的索引,这发生在指定的起始索引或之后的索引上。 |
19 | void or(BitSet bitSet) 对此位 set 和位 set 参数执行逻辑或操作。 |
20 | void set(int index) 将指定索引处的位设置为 true。 |
21 | void set(int index, boolean v) 将指定索引处的位设置为指定的值。 |
22 | void set(int startIndex, int endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 true。 |
23 | void set(int startIndex, int endIndex, boolean v) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为指定的值。 |
24 | int size( ) 返回此 BitSet 表示位值时实际使用空间的位数。 |
25 | String toString( ) 返回此位 set 的字符串表示形式。 |
26 | void xor(BitSet bitSet) 对此位 set 和位 set 参数执行逻辑异或操作。 |
package three; import java.util.BitSet; public class myBitset {<br/> public static void main(String[] args){<br/> BitSet bits1 = new BitSet(16);<br/> BitSet bits2 = new BitSet(16); // set some bits<br/> for(int i=0; i<16; i++) {<br/> if((i%2) == 0) bits1.set(i);<br/> if((i%5) != 0) bits2.set(i);<br/> }<br/> System.out.println("Initial pattern in bits1: ");<br/> System.out.println(bits1); // {0, 2, 4, 6, 8, 10, 12, 14}<br/> System.out.println("\nInitial pattern in bits2: ");<br/> System.out.println(bits2); // {1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14} // AND bits<br/> bits2.and(bits1);<br/> System.out.println("\nbits2 AND bits1: ");<br/> System.out.println(bits1); // {0, 2, 4, 6, 8, 10, 12, 14}<br/> System.out.println(bits2); // {2, 4, 6, 8, 12, 14} // OR bits<br/> bits2.or(bits1);<br/> System.out.println("\nbits2 OR bits1: ");<br/> System.out.println(bits1); // {0, 2, 4, 6, 8, 10, 12, 14}<br/> System.out.println(bits2); // {0, 2, 4, 6, 8, 10, 12, 14} // XOR bits<br/> bits2.xor(bits1);<br/> System.out.println("\nbits2 XOR bits1: ");<br/> System.out.println(bits1); // {0, 2, 4, 6, 8, 10, 12, 14}<br/> System.out.println(bits2); // {}<br/> }<br/> }
practice
向量(Vector)
向量(Vector)类和传统数组非常相似,但是Vector的大小能根据需要动态的变化。
和数组一样,Vector对象的元素也能通过索引访问。
使用Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。
Vector类实现了一个动态数组。和ArrayList和相似,但是两者是不同的:
- Vector是同步访问的。
- Vector包含了许多传统的方法,这些方法不属于集合框架。
Vector主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
Vector类支持4种构造方法。
Vector() //第一种构造方法创建一个默认的向量,默认大小为10<br/> Vector(int size) //第二种构造方法创建指定大小的向量<br/> Vector(int size,int incr) //第三种构造方法创建指定大小的向量,并且增量用incr指定. 增量表示向量每次增加的元素数目<br/> Vector(Collection c) //第四中构造方法创建一个包含集合c元素的向量
除了从父类继承的方法外Vector还定义了以下方法:
序号 | 方法描述 |
---|---|
1 | void add(int index, Object element) 在此向量的指定位置插入指定的元素。 |
2 | boolean add(Object o) 将指定元素添加到此向量的末尾。 |
3 | boolean addAll(Collection c) 将指定 Collection 中的所有元素添加到此向量的末尾,按照指定 collection 的迭代器所返回的顺序添加这些元素。 |
4 | boolean addAll(int index, Collection c) 在指定位置将指定 Collection 中的所有元素插入到此向量中。 |
5 | void addElement(Object obj) 将指定的组件添加到此向量的末尾,将其大小增加 1。 |
6 | int capacity() 返回此向量的当前容量。 |
7 | void clear() 从此向量中移除所有元素。 |
8 | Object clone() 返回向量的一个副本。 |
9 | boolean contains(Object elem) 如果此向量包含指定的元素,则返回 true。 |
10 | boolean containsAll(Collection c) 如果此向量包含指定 Collection 中的所有元素,则返回 true。 |
11 | void copyInto(Object[] anArray) 将此向量的组件复制到指定的数组中。 |
12 | Object elementAt(int index) 返回指定索引处的组件。 |
13 | Enumeration elements() 返回此向量的组件的枚举。 |
14 | void ensureCapacity(int minCapacity) 增加此向量的容量(如有必要),以确保其至少能够保存最小容量参数指定的组件数。 |
15 | boolean equals(Object o) 比较指定对象与此向量的相等性。 |
16 | Object firstElement() 返回此向量的第一个组件(位于索引 0) 处的项)。 |
17 | Object get(int index) 返回向量中指定位置的元素。 |
18 | int hashCode() 返回此向量的哈希码值。 |
19 | int indexOf(Object elem) 返回此向量中第一次出现的指定元素的索引,如果此向量不包含该元素,则返回 -1。 |
20 | int indexOf(Object elem, int index) 返回此向量中第一次出现的指定元素的索引,从 index 处正向搜索,如果未找到该元素,则返回 -1。 |
21 | void insertElementAt(Object obj, int index) 将指定对象作为此向量中的组件插入到指定的 index 处。 |
22 | boolean isEmpty() 测试此向量是否不包含组件。 |
23 | Object lastElement() 返回此向量的最后一个组件。 |
24 | int lastIndexOf(Object elem) 返回此向量中最后一次出现的指定元素的索引;如果此向量不包含该元素,则返回 -1。 |
25 | int lastIndexOf(Object elem, int index) 返回此向量中最后一次出现的指定元素的索引,从 index 处逆向搜索,如果未找到该元素,则返回 -1。 |
26 | Object remove(int index) 移除此向量中指定位置的元素。 |
27 | boolean remove(Object o) 移除此向量中指定元素的第一个匹配项,如果向量不包含该元素,则元素保持不变。 |
28 | boolean removeAll(Collection c) 从此向量中移除包含在指定 Collection 中的所有元素。 |
29 | void removeAllElements() 从此向量中移除全部组件,并将其大小设置为零。 |
30 | boolean removeElement(Object obj) 从此向量中移除变量的第一个(索引最小的)匹配项。 |
31 | void removeElementAt(int index) 删除指定索引处的组件。 |
32 | protected void removeRange(int fromIndex, int toIndex) 从此 List 中移除其索引位于 fromIndex(包括)与 toIndex(不包括)之间的所有元素。 |
33 | boolean retainAll(Collection c) 在此向量中仅保留包含在指定 Collection 中的元素。 |
34 | Object set(int index, Object element) 用指定的元素替换此向量中指定位置处的元素。 |
35 | void setElementAt(Object obj, int index) 将此向量指定 index 处的组件设置为指定的对象。 |
36 | void setSize(int newSize) 设置此向量的大小。 |
37 | int size() 返回此向量中的组件数。 |
38 | List subList(int fromIndex, int toIndex) 返回此 List 的部分视图,元素范围为从 fromIndex(包括)到 toIndex(不包括)。 |
39 | Object[] toArray() 返回一个数组,包含此向量中以恰当顺序存放的所有元素。 |
40 | Object[] toArray(Object[] a) 返回一个数组,包含此向量中以恰当顺序存放的所有元素;返回数组的运行时类型为指定数组的类型。 |
41 | String toString() 返回此向量的字符串表示形式,其中包含每个元素的 String 表示形式。 |
42 | void trimToSize() 对此向量的容量进行微调,使其等于向量的当前大小。 |
package three; import java.util.*; public class myVector {<br/> public static void main(String[] args){<br/> Vector v = new Vector(3, 2);<br/> System.out.println(v.size()); //<br/> System.out.println(v.capacity()); //<br/> v.addElement(new Integer(1));<br/> System.out.println(v.capacity()); //<br/> v.addElement(new Integer(2));<br/> System.out.println(v.capacity()); //<br/> v.addElement(new Integer(3));<br/> System.out.println(v.capacity()); // v.addElement(new Integer(4));<br/> System.out.println(v.capacity()); //<br/> v.addElement(new Double(5.45));<br/> System.out.println(v.capacity()); // v.addElement(new Double(6.08));<br/> v.addElement(new Integer(7));<br/> System.out.println(v.capacity()); //<br/> v.addElement(new Float(9.4));<br/> v.addElement(new Integer(10));<br/> System.out.println(v.capacity()); //<br/> v.addElement(new Integer(11));<br/> v.addElement(new Integer(12));<br/> System.out.println(v.capacity()); //<br/> System.out.println((Integer)v.firstElement()); //<br/> System.out.println((Integer)v.lastElement()); // if(v.contains(new Integer(3)))<br/> System.out.println("Vector contains 3."); //true // enumerate the elements in the vector.<br/> Enumeration vEnum = v.elements();<br/> System.out.println("\nElements in vector:");<br/> while(vEnum.hasMoreElements())<br/> System.out.print(vEnum.nextElement() + " ");<br/> // 1 2 3 4 5.45 6.08 7 9.4 10 11 12<br/> System.out.println();<br/> }<br/> }
practice
栈(Stack)
栈(Stack)实现了一个后进先出(LIFO)的数据结构。
你可以把栈理解为对象的垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。
当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出。
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
Stack()
除了由Vector定义的所有方法,自己也定义了一些方法:
序号 | 方法描述 |
---|---|
1 | boolean empty() 测试堆栈是否为空。 |
2 | Object peek( ) 查看堆栈顶部的对象,但不从堆栈中移除它。 |
3 | Object pop( ) 移除堆栈顶部的对象,并作为此函数的值返回该对象。 |
4 | Object push(Object element) 把项压入堆栈顶部。 |
5 | int search(Object element) 返回对象在堆栈中的位置,以 1 为基数。 |
package three; import java.util.*; public class myStack {<br/> static void showpush(Stack st, int a) {<br/> st.push(new Integer(a));<br/> System.out.println("push(" + a + ")");<br/> System.out.println("stack: " + st);<br/> } static void showpop(Stack st) {<br/> System.out.print("pop -> ");<br/> Integer a = (Integer) st.pop();<br/> System.out.println(a);<br/> System.out.println("stack: " + st);<br/> } public static void main(String args[]) {<br/> Stack st = new Stack();<br/> System.out.println("stack: " + st);<br/> showpush(st, 42);<br/> showpush(st, 66);<br/> showpush(st, 99);<br/> showpop(st);<br/> showpop(st);<br/> showpop(st);<br/> try {<br/> showpop(st);<br/> } catch (EmptyStackException e) {<br/> System.out.println("empty stack");<br/> }<br/> }<br/> /*输出结果:<br/> stack: []<br/> push(42)<br/> stack: [42]<br/> push(66)<br/> stack: [42, 66]<br/> push(99)<br/> stack: [42, 66, 99]<br/> pop -> 99<br/> stack: [42, 66]<br/> pop -> 66<br/> stack: [42]<br/> pop -> 42<br/> stack: []<br/> pop -> empty stack<br/> * */<br/> }
practice
字典(Dictionary)
字典(Dictionary) 类是一个抽象类,它定义了键映射到值的数据结构。
当你想要通过特定的键而不是整数索引来访问数据的时候,这时候应该使用Dictionary。
由于Dictionary类是抽象类,所以它只提供了键映射到值的数据结构,而没有提供特定的实现。
Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。
给出键和值,你就可以将值存储在Dictionary对象中。一旦该值被存储,就可以通过它的键来获取它。所以和Map一样, Dictionary 也可以作为一个键/值对列表。
Dictionary定义的抽象方法如下表所示:
序号 | 方法描述 |
1 | Enumeration elements( ) 返回此 dictionary 中值的枚举。 |
2 | Object get(Object key) 返回此 dictionary 中该键所映射到的值。 |
3 | boolean isEmpty( ) 测试此 dictionary 是否不存在从键到值的映射。 |
4 | Enumeration keys( ) 返回此 dictionary 中的键的枚举。 |
5 | Object put(Object key, Object value) 将指定 key 映射到此 dictionary 中指定 value。 |
6 | Object remove(Object key) 从此 dictionary 中移除 key (及其相应的 value)。 |
7 | int size( ) 返回此 dictionary 中条目(不同键)的数量。 |
哈希表(Hashtable)
Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。
例如,在地址列表的哈希表中,你可以根据邮政编码作为键来存储和排序数据,而不是通过人名。
哈希表键的具体含义完全取决于哈希表的使用情景和它包含的数据。
Hashtable是原始的java.util的一部分, 是一个Dictionary具体的实现 。
然而,Java 2 重构的Hashtable实现了Map接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步。
像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。
然后,该键经过哈希处理,所得到的散列码被用作存储在该表中值的索引。
Hashtable定义了四个构造方法。
Hashtable()<br/> Hashtable(int size) //创建指定大小的哈希表<br/> Hashtable(int size,float fillRatio) //创建一个指定大小的哈希表,并且通过fillRatio指定填充比例。填充比例必须介于0.0和1.0之间,它决定了哈希表在重新调整大小之前的充满程度<br/> Hashtable(Map m) //创建一个以M中元素为初始化元素的哈希表。哈希表的容量被设置为M的两倍。
Hashtable中除了从Map接口中定义的方法外,还定义了以下方法:
序号 | 方法描述 |
---|---|
1 | void clear( ) 将此哈希表清空,使其不包含任何键。 |
2 | Object clone( ) 创建此哈希表的浅表副本。 |
3 | boolean contains(Object value) 测试此映射表中是否存在与指定值关联的键。 |
4 | boolean containsKey(Object key) 测试指定对象是否为此哈希表中的键。 |
5 | boolean containsValue(Object value) 如果此 Hashtable 将一个或多个键映射到此值,则返回 true。 |
6 | Enumeration elements( ) 返回此哈希表中的值的枚举。 |
7 | Object get(Object key) 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,则此方法返回 v;否则,返回 null。 |
8 | boolean isEmpty( ) 测试此哈希表是否没有键映射到值。 |
9 | Enumeration keys( ) 返回此哈希表中的键的枚举。 |
10 | Object put(Object key, Object value) 将指定 key 映射到此哈希表中的指定 value。 |
11 | void rehash( ) 增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。 |
12 | Object remove(Object key) 从哈希表中移除该键及其相应的值。 |
13 | int size( ) 返回此哈希表中的键的数量。 |
14 | String toString( ) 返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 “, ” (逗号加空格)分隔开的、括在括号中的一组条目。 |
package three; import java.util.*; public class myHashTable {<br/> public static void main(String args[]) {<br/> // Create a hash map<br/> Hashtable balance = new Hashtable();<br/> Enumeration names;<br/> String str;<br/> double bal; balance.put("Zara", new Double(3434.34));<br/> balance.put("Mahnaz", new Double(123.22));<br/> balance.put("Ayan", new Double(1378.00));<br/> balance.put("Daisy", new Double(99.22));<br/> balance.put("Qadir", new Double(-19.08)); // Show all balances in hash table.<br/> names = balance.keys();<br/> while(names.hasMoreElements()) {<br/> str = (String) names.nextElement();<br/> System.out.println(str + ": " +<br/> balance.get(str));<br/> }<br/> System.out.println();<br/> // Deposit 1,000 into Zara's account<br/> bal = ((Double)balance.get("Zara")).doubleValue();<br/> balance.put("Zara", new Double(bal+1000));<br/> System.out.println("Zara's new balance: " +<br/> balance.get("Zara"));<br/> } /*输出结果<br/> Qadir: -19.08<br/> Zara: 3434.34<br/> Mahnaz: 123.22<br/> Daisy: 99.22<br/> Ayan: 1378.0 Zara's new balance: 4434.34<br/> * */<br/> }
practice
属性(Properties)
Properties 继承于 Hashtable.Properties 类表示了一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。
Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。
Properties 定义如下实例变量.这个变量持有一个Properties对象相关的默认属性列表。
Properties defaults;
Properties类定义了两个构造方法。
Properties() //第一个构造方法没有默认值。<br/> Properties(Properties propDefault) //使用propDefault 作为默认值。<br/> 两种情况下,属性列表都为空
除了从Hashtable中所定义的方法,Properties定义了以下方法:
序号 | 方法描述 |
---|---|
1 | String getProperty(String key) 用指定的键在此属性列表中搜索属性。 |
2 | String getProperty(String key, String defaultProperty) 用指定的键在属性列表中搜索属性。 |
3 | void list(PrintStream streamOut) 将属性列表输出到指定的输出流。 |
4 | void list(PrintWriter streamOut) 将属性列表输出到指定的输出流。 |
5 | void load(InputStream streamIn) throws IOException 从输入流中读取属性列表(键和元素对)。 |
6 | Enumeration propertyNames( ) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 |
7 | Object setProperty(String key, String value) 调用 Hashtable 的方法 put。 |
8 | void store(OutputStream streamOut, String description) 以适合使用 load(InputStream)方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。 |
package three; import java.util.*; public class myProperties {<br/> public static void main(String args[]) {<br/> Properties capitals = new Properties();<br/> Set states;<br/> String str; capitals.put("Illinois", "Springfield");<br/> capitals.put("Missouri", "Jefferson City");<br/> capitals.put("Washington", "Olympia");<br/> capitals.put("California", "Sacramento");<br/> capitals.put("Indiana", "Indianapolis"); // Show all states and capitals in hashtable.<br/> states = capitals.keySet(); // get set-view of keys<br/> Iterator itr = states.iterator();<br/> while(itr.hasNext()) {<br/> str = (String) itr.next();<br/> System.out.println("The capital of " +<br/> str + " is " + capitals.getProperty(str) + ".");<br/> }<br/> System.out.println(); // look for state not in list -- specify default<br/> str = capitals.getProperty("Florida", "Not Found");<br/> System.out.println("The capital of Florida is "<br/> + str + ".");<br/> } /*输出结果<br/> * The capital of Missouri is Jefferson City.<br/> The capital of Illinois is Springfield.<br/> The capital of Indiana is Indianapolis.<br/> The capital of California is Sacramento.<br/> The capital of Washington is Olympia. The capital of Florida is Not Found.<br/> * */<br/> }
practice
三、泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
泛型的好处
Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:
类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。
Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“String 列表”或者“String 到 String 的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException 展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。
消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程度,但是声明泛型变量会带来相应的啰嗦。
泛型方法
你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
下面是定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
实例
下面的例子演示了如何使用泛型方法打印不同字符串的元素:
public class GenericMethodTest<br/> {<br/> // 泛型方法 printArray<br/> public static < E > void printArray( E[] inputArray )<br/> {<br/> // 输出数组元素<br/> for ( E element : inputArray ){<br/> System.out.printf( "%s ", element );<br/> }<br/> System.out.println();<br/> } public static void main( String args[] )<br/> {<br/> // 创建不同类型数组: Integer, Double 和 Character<br/> Integer[] intArray = { 1, 2, 3, 4, 5 };<br/> Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };<br/> Character[] charArray = { 'H', 'E', 'L', 'L', 'O' }; System.out.println( "整型数组元素为:" );<br/> printArray( intArray ); // 传递一个整型数组 System.out.println( "\n双精度型数组元素为:" );<br/> printArray( doubleArray ); // 传递一个双精度型数组 System.out.println( "\n字符型数组元素为:" );<br/> printArray( charArray ); // 传递一个字符型数组<br/> }<br/> } /*输出结果<br/> 整型数组元素为:<br/> 1 2 3 4 5 双精度型数组元素为:<br/> 1.1 2.2 3.3 4.4 字符型数组元素为:<br/> H E L L O<br/> * */
有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
下面的例子演示了”extends”如何使用在一般意义上的意思”extends”(类)或者”implements”(接口)。该例子中的泛型方法返回三个可比较对象的最大值。
public class MaximumTest<br/> {<br/> // 比较三个值并返回最大值<br/> public static <T extends Comparable<T>> T maximum(T x, T y, T z)<br/> {<br/> T max = x; // 假设x是初始最大值<br/> if ( y.compareTo( max ) > 0 ){<br/> max = y; //y 更大<br/> }<br/> if ( z.compareTo( max ) > 0 ){<br/> max = z; // 现在 z 更大<br/> }<br/> return max; // 返回最大对象<br/> }<br/> public static void main( String args[] )<br/> {<br/> System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",<br/> 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",<br/> 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) ); System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",<br/> "apple", "orange", maximum( "pear", "apple", "orange" ) );<br/> }<br/> } /*输出结果<br/> 3, 4 和 5 中最大的数为 5 6.6, 8.8 和 7.7 中最大的数为 8.8 pear, apple 和 orange 中最大的数为 pear<br/> */
泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
如下实例演示了我们如何定义一个泛型类:
public class Box<T> { private T t; public void add(T t) {<br/> this.t = t;<br/> } public T get() {<br/> return t;<br/> } public static void main(String[] args) {<br/> Box<Integer> integerBox = new Box<Integer>();<br/> Box<String> stringBox = new Box<String>(); integerBox.add(new Integer(10));<br/> stringBox.add(new String("嗨..")); System.out.printf("整型值为 :%d\n\n", integerBox.get());<br/> System.out.printf("字符串为 :%s\n", stringBox.get());<br/> }<br/> }<br/> /*<br/> 整型值为 :10 字符串为 :嗨..<br/> */
泛型类型通配符
类型通配符一般是使用?代替具体的类型参数
例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
package three; import java.util.ArrayList;<br/> import java.util.List; public class GenericTest {<br/> public static void main(String[] args) {<br/> List<String> name = new ArrayList<String>();<br/> List<Integer> age = new ArrayList<Integer>();<br/> List<Number> number = new ArrayList<Number>(); name.add("nick");<br/> age.add(18);<br/> number.add(530); getData(name);<br/> getData(age);<br/> getData(number); // getUperNumber(name); //报错<br/> getUperNumber(age);<br/> getUperNumber(number);<br/> } public static void getData(List<?> data) {<br/> System.out.println("getData :" + data.get(0));<br/> } public static void getUperNumber(List<? extends Number> data) {<br/> System.out.println("getUperNumber :" + data.get(0));<br/> }<br/> } /*输出结果<br/> * getData :nick<br/> getData :18<br/> getData :530<br/> getUperNumber :18<br/> getUperNumber :530<br/> * */