一起学 Java(三) 集合框架、数据结构、泛型

一、Java 集合框架

集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:

  • 接口:是代表集合的抽象数据类型。接口允许集合独立操纵其代表的细节。在面向对象的语言,接口通常形成一个层次。
  • 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构。
  • 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。

集合接口

序号name接口描述
1Collection

Collection 是最基本的集合接口,一个 Collection 代表一组 Object,Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。

2List

List接口是一个有序的Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的小标)来访问List中的元素,而且允许有相同的元素。

3Set

Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。

4SortedSet继承于Set保存有序的集合。
5Map将唯一的键映射到值。
6Map.Entry描述在一个Map中的一个元素(键/值对)。是一个Map的内部类。
7SortedMap继承于Map,使Key保持在升序排列。
8Enumeration这是一个传统的接口和定义的方法,通过它可以枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代。

集合实现类(集合类)

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 HashMapHashMap 是一个散列表,它存储的内容是键值对(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 HashtableHashtable 是 Dictionary(字典) 类的子类,位于 java.util 包中。

5 Properties Properties 继承于 Hashtable,表示一个持久的属性集,属性列表中每个键及其对应值都是一个字符串。
6 BitSet一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
 
public class myArrayList {
    public static void main(String[] args){
        List<String> list = new ArrayList<String>();
        list.add("nick");
        list.add("jenny");
        list.add("Maria");
 
        //第一种遍历方法使用foreach遍历List
        for (String str : list){
            System.out.println(str);
        }
 
        //第二种遍历,把链表变为数组相关的内容进行遍历
        String[] strArray = new String[list.size()];
        list.toArray(strArray);
        for (int i=0;i<strArray.length;i++){
            System.out.println(strArray[i]);
        }
 
        //第三种遍历 使用迭代器进行相关遍历
        Iterator<String> ite=list.iterator();
        while (ite.hasNext()){
            System.out.println(ite.next());
        }
    }
}

myArrayList.java

package three;
 
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class mymap {
    public static void main(String[] args){
        Map<String, String> map = new HashMap<String, String>();
        map.put("name", "nick");
        map.put("age", "18");
        map.put("single", "singleDog");
 
        //第一种:普遍使用,二次取值
        for (String key : map.keySet()){
            System.out.println(key + " " + map.get(key));
        }
 
        //通过Map.entrySet使用iterator遍历key和value
        Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
 
        //第三种:推荐,尤其是容量大时
        for (Map.Entry<String, String> entry : map.entrySet()){
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
 
        //通过Map.values()遍历所有的value,但不能遍历key
        for (String v : map.values()){
            System.out.println(v);
        }
    }
}

mymap.java

二、Java数据结构

在Java中的数据结构主要包括以下几种接口和类:

  • 枚举(Enumeration)
  • 位集合(BitSet)
  • 向量(Vector)
  • 栈(Stack)
  • 字典(Dictionary)
  • 哈希表(Hashtable)
  • 属性(Properties)

枚举(Enumeration)

Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素。

这种传统接口已被迭代器取代,虽然Enumeration 还未被遗弃,但在现代代码中已经被很少使用了。尽管如此,它还是使用在诸如Vector和Properties这些传统类所定义的方法中,除此之外,还用在一些API类,并且在应用程序中也广泛被使用。 下表总结了一些Enumeration声明的方法:

序号方法描述
1boolean hasMoreElements( )
 测试此枚举是否包含更多的元素。
2Object nextElement( )
如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。

package three;
 
import java.util.Vector;
import java.util.Enumeration;
 
public class myEnumeration {
    public static void main(String[] args){
        Enumeration days;
        Vector dayNames = new Vector();
        dayNames.add("Sunday");
        dayNames.add("Monday");
        dayNames.add("Tuesday");
        dayNames.add("Wednesday");
        dayNames.add("Thursday");
        dayNames.add("Friday");
        dayNames.add("Saturday");
        days = dayNames.elements();
        while (days.hasMoreElements()){
           System.out.println(days.nextElement());
        }
    }
}

practice

位集合(BitSet)

位集合类实现了一组可以单独设置和清除的位或标志。

该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一"位",然后对位进行适当的设置或清除,就可以对布尔值进行操作了。

一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。这和位向量(vector of bits)比较类似。

这是一个传统的类,但它在Java 2中被完全重新设计。

BitSet定义了两个构造方法。

BitSet()    //第一个构造方法创建一个默认的对象
BitSet(int size)    //第二个方法允许用户指定初始大小。所有位初始化为0。

BitSet中实现了Cloneable接口中定义的方法如下表所列:

序号方法描述
1void and(BitSet bitSet)
对此目标位 set 和参数位 set 执行逻辑与操作。
2void andNot(BitSet bitSet)
清除此 BitSet 中所有的位,其相应的位在指定的 BitSet 中已设置。
3int cardinality( )
返回此 BitSet 中设置为 true 的位数。
4void clear( )
将此 BitSet 中的所有位设置为 false。
5void clear(int index)
将索引指定处的位设置为 false。
6void clear(int startIndex, int endIndex)
将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 false。
7Object clone( )
复制此 BitSet,生成一个与之相等的新 BitSet。
8boolean equals(Object bitSet)
将此对象与指定的对象进行比较。
9void flip(int index)
将指定索引处的位设置为其当前值的补码。
10void flip(int startIndex, int endIndex)
将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的每个位设置为其当前值的补码。
11boolean get(int index)
返回指定索引处的位值。
12BitSet get(int startIndex, int endIndex)
返回一个新的 BitSet,它由此 BitSet 中从 fromIndex(包括)到 toIndex(不包括)范围内的位组成。
13int hashCode( )
返回此位 set 的哈希码值。
14boolean intersects(BitSet bitSet)
如果指定的 BitSet 中有设置为 true 的位,并且在此 BitSet 中也将其设置为 true,则返回 ture。
15boolean isEmpty( )
如果此 BitSet 中没有包含任何设置为 true 的位,则返回 ture。
16int length( )
返回此 BitSet 的"逻辑大小":BitSet 中最高设置位的索引加 1。
17int nextClearBit(int startIndex)
返回第一个设置为 false 的位的索引,这发生在指定的起始索引或之后的索引上。
18int nextSetBit(int startIndex)
返回第一个设置为 true 的位的索引,这发生在指定的起始索引或之后的索引上。
19void or(BitSet bitSet)
对此位 set 和位 set 参数执行逻辑或操作。
20void set(int index)
将指定索引处的位设置为 true。
21void set(int index, boolean v)
 将指定索引处的位设置为指定的值。
22void set(int startIndex, int endIndex)
将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 true。
23void set(int startIndex, int endIndex, boolean v)
将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为指定的值。
24int size( )
返回此 BitSet 表示位值时实际使用空间的位数。
25String toString( )
返回此位 set 的字符串表示形式。
26void xor(BitSet bitSet)
对此位 set 和位 set 参数执行逻辑异或操作。

package three;
 
import java.util.BitSet;
 
public class myBitset {
    public static void main(String[] args){
        BitSet bits1 = new BitSet(16);
        BitSet bits2 = new BitSet(16);
 
        // set some bits
        for(int i=0; i<16; i++) {
            if((i%2) == 0) bits1.set(i);
            if((i%5) != 0) bits2.set(i);
        }
        System.out.println("Initial pattern in bits1: ");
        System.out.println(bits1);    // {0, 2, 4, 6, 8, 10, 12, 14}
        System.out.println("\nInitial pattern in bits2: ");
        System.out.println(bits2);    // {1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14}
 
        // AND bits
        bits2.and(bits1);
        System.out.println("\nbits2 AND bits1: ");
        System.out.println(bits1);    // {0, 2, 4, 6, 8, 10, 12, 14}
        System.out.println(bits2);    // {2, 4, 6, 8, 12, 14}
 
        // OR bits
        bits2.or(bits1);
        System.out.println("\nbits2 OR bits1: ");
        System.out.println(bits1);    // {0, 2, 4, 6, 8, 10, 12, 14}
        System.out.println(bits2);    // {0, 2, 4, 6, 8, 10, 12, 14}
 
        // XOR bits
        bits2.xor(bits1);
        System.out.println("\nbits2 XOR bits1: ");
        System.out.println(bits1);    // {0, 2, 4, 6, 8, 10, 12, 14}
        System.out.println(bits2);    // {}
    }
}

practice

向量(Vector)

向量(Vector)类和传统数组非常相似,但是Vector的大小能根据需要动态的变化。

和数组一样,Vector对象的元素也能通过索引访问。

使用Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。

Vector类实现了一个动态数组。和ArrayList和相似,但是两者是不同的:

  • Vector是同步访问的。
  • Vector包含了许多传统的方法,这些方法不属于集合框架。

Vector主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。

Vector类支持4种构造方法。

Vector()    //第一种构造方法创建一个默认的向量,默认大小为10
Vector(int size)    //第二种构造方法创建指定大小的向量
Vector(int size,int incr)    //第三种构造方法创建指定大小的向量,并且增量用incr指定. 增量表示向量每次增加的元素数目
Vector(Collection c)    //第四中构造方法创建一个包含集合c元素的向量

除了从父类继承的方法外Vector还定义了以下方法:

序号方法描述
1void add(int index, Object element) 
 在此向量的指定位置插入指定的元素。
2boolean add(Object o) 
 将指定元素添加到此向量的末尾。
3boolean addAll(Collection c) 
将指定 Collection 中的所有元素添加到此向量的末尾,按照指定 collection 的迭代器所返回的顺序添加这些元素。
4boolean addAll(int index, Collection c) 
在指定位置将指定 Collection 中的所有元素插入到此向量中。
5void addElement(Object obj) 
 将指定的组件添加到此向量的末尾,将其大小增加 1。
6int capacity() 
返回此向量的当前容量。
7void clear() 
从此向量中移除所有元素。
8Object clone() 
返回向量的一个副本。
9boolean contains(Object elem) 
如果此向量包含指定的元素,则返回 true。
10boolean containsAll(Collection c) 
如果此向量包含指定 Collection 中的所有元素,则返回 true。
11void copyInto(Object[] anArray) 
 将此向量的组件复制到指定的数组中。
12Object elementAt(int index) 
返回指定索引处的组件。
13Enumeration elements() 
返回此向量的组件的枚举。
14void ensureCapacity(int minCapacity) 
增加此向量的容量(如有必要),以确保其至少能够保存最小容量参数指定的组件数。
15boolean equals(Object o) 
比较指定对象与此向量的相等性。
16Object firstElement() 
返回此向量的第一个组件(位于索引 0) 处的项)。
17Object get(int index) 
返回向量中指定位置的元素。
18int hashCode() 
返回此向量的哈希码值。
19int indexOf(Object elem) 
 返回此向量中第一次出现的指定元素的索引,如果此向量不包含该元素,则返回 -1。
20int indexOf(Object elem, int index) 
 返回此向量中第一次出现的指定元素的索引,从 index 处正向搜索,如果未找到该元素,则返回 -1。
21void insertElementAt(Object obj, int index) 
将指定对象作为此向量中的组件插入到指定的 index 处。
22boolean isEmpty() 
测试此向量是否不包含组件。
23Object lastElement() 
返回此向量的最后一个组件。
24int lastIndexOf(Object elem) 
 返回此向量中最后一次出现的指定元素的索引;如果此向量不包含该元素,则返回 -1。
25int lastIndexOf(Object elem, int index) 
返回此向量中最后一次出现的指定元素的索引,从 index 处逆向搜索,如果未找到该元素,则返回 -1。
26Object remove(int index) 
 移除此向量中指定位置的元素。
27boolean remove(Object o) 
移除此向量中指定元素的第一个匹配项,如果向量不包含该元素,则元素保持不变。
28boolean removeAll(Collection c) 
从此向量中移除包含在指定 Collection 中的所有元素。
29void removeAllElements() 
从此向量中移除全部组件,并将其大小设置为零。
30boolean removeElement(Object obj) 
从此向量中移除变量的第一个(索引最小的)匹配项。
31void removeElementAt(int index) 
删除指定索引处的组件。
32protected void removeRange(int fromIndex, int toIndex)
从此 List 中移除其索引位于 fromIndex(包括)与 toIndex(不包括)之间的所有元素。
33boolean retainAll(Collection c) 
在此向量中仅保留包含在指定 Collection 中的元素。
34Object set(int index, Object element)
 用指定的元素替换此向量中指定位置处的元素。
35void setElementAt(Object obj, int index) 
将此向量指定 index 处的组件设置为指定的对象。
36void setSize(int newSize) 
 设置此向量的大小。
37int size() 
 返回此向量中的组件数。
38List subList(int fromIndex, int toIndex) 
返回此 List 的部分视图,元素范围为从 fromIndex(包括)到 toIndex(不包括)。
39Object[] toArray()
 返回一个数组,包含此向量中以恰当顺序存放的所有元素。
40Object[] toArray(Object[] a) 
返回一个数组,包含此向量中以恰当顺序存放的所有元素;返回数组的运行时类型为指定数组的类型。
41String toString() 
返回此向量的字符串表示形式,其中包含每个元素的 String 表示形式。
42void trimToSize() 
  对此向量的容量进行微调,使其等于向量的当前大小。

package three;
 
import java.util.*;
 
public class myVector {
    public static void main(String[] args){
          Vector v = new Vector(3, 2);
          System.out.println(v.size());    //
          System.out.println(v.capacity());    //
          v.addElement(new Integer(1));
          System.out.println(v.capacity());    //
          v.addElement(new Integer(2));
          System.out.println(v.capacity());    //
          v.addElement(new Integer(3));
          System.out.println(v.capacity());    //
 
          v.addElement(new Integer(4));
          System.out.println(v.capacity());    //
          v.addElement(new Double(5.45));
          System.out.println(v.capacity());    //
 
          v.addElement(new Double(6.08));
          v.addElement(new Integer(7));
          System.out.println(v.capacity());    //
          v.addElement(new Float(9.4));
          v.addElement(new Integer(10));
          System.out.println(v.capacity());    //
          v.addElement(new Integer(11));
          v.addElement(new Integer(12));
          System.out.println(v.capacity());    //
          System.out.println((Integer)v.firstElement()); //
          System.out.println((Integer)v.lastElement());    //
 
          if(v.contains(new Integer(3)))
             System.out.println("Vector contains 3.");    //true
 
          // enumerate the elements in the vector.
          Enumeration vEnum = v.elements();
          System.out.println("\nElements in vector:");
          while(vEnum.hasMoreElements())
             System.out.print(vEnum.nextElement() + " ");
               // 1 2 3 4 5.45 6.08 7 9.4 10 11 12
          System.out.println();
    }
}

practice

栈(Stack)

栈(Stack)实现了一个后进先出(LIFO)的数据结构。

你可以把栈理解为对象的垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。

当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出。

栈是Vector的一个子类,它实现了一个标准的后进先出的栈。

堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。

Stack()

除了由Vector定义的所有方法,自己也定义了一些方法:

序号方法描述
1boolean empty() 
测试堆栈是否为空。
2Object peek( )
查看堆栈顶部的对象,但不从堆栈中移除它。
3Object pop( )
移除堆栈顶部的对象,并作为此函数的值返回该对象。
4Object push(Object element)
把项压入堆栈顶部。
5int search(Object element)
返回对象在堆栈中的位置,以 1 为基数。

package three;
 
import java.util.*;
 
public class myStack {
       static void showpush(Stack st, int a) {
          st.push(new Integer(a));
          System.out.println("push(" + a + ")");
          System.out.println("stack: " + st);
       }
 
       static void showpop(Stack st) {
          System.out.print("pop -> ");
          Integer a = (Integer) st.pop();
          System.out.println(a);
          System.out.println("stack: " + st);
       }
 
       public static void main(String args[]) {
          Stack st = new Stack();
          System.out.println("stack: " + st);
          showpush(st, 42);
          showpush(st, 66);
          showpush(st, 99);
          showpop(st);
          showpop(st);
          showpop(st);
          try {
               showpop(st);
             } catch (EmptyStackException e) {
               System.out.println("empty stack");
          }
       }
       /*输出结果:
        stack: []
        push(42)
        stack: [42]
        push(66)
        stack: [42, 66]
        push(99)
        stack: [42, 66, 99]
        pop -> 99
        stack: [42, 66]
        pop -> 66
        stack: [42]
        pop -> 42
        stack: []
        pop -> empty stack
        * */
}

ractice

字典(Dictionary)

字典(Dictionary) 类是一个抽象类,它定义了键映射到值的数据结构。

当你想要通过特定的键而不是整数索引来访问数据的时候,这时候应该使用Dictionary。

由于Dictionary类是抽象类,所以它只提供了键映射到值的数据结构,而没有提供特定的实现。

Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。

给出键和值,你就可以将值存储在Dictionary对象中。一旦该值被存储,就可以通过它的键来获取它。所以和Map一样, Dictionary 也可以作为一个键/值对列表。

Dictionary定义的抽象方法如下表所示:

序号方法描述
1Enumeration elements( )
返回此 dictionary 中值的枚举。
2Object get(Object key)
返回此 dictionary 中该键所映射到的值。
3boolean isEmpty( )
测试此 dictionary 是否不存在从键到值的映射。
4Enumeration keys( )
返回此 dictionary 中的键的枚举。
5Object put(Object key, Object value)
将指定 key 映射到此 dictionary 中指定 value。
6Object remove(Object key)
从此 dictionary 中移除 key (及其相应的 value)。
7int size( )
返回此 dictionary 中条目(不同键)的数量。

哈希表(Hashtable)

Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。

例如,在地址列表的哈希表中,你可以根据邮政编码作为键来存储和排序数据,而不是通过人名。

哈希表键的具体含义完全取决于哈希表的使用情景和它包含的数据。

Hashtable是原始的java.util的一部分, 是一个Dictionary具体的实现 。

然而,Java 2 重构的Hashtable实现了Map接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步。

像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。

然后,该键经过哈希处理,所得到的散列码被用作存储在该表中值的索引。

Hashtable定义了四个构造方法。

Hashtable()
Hashtable(int size)    //创建指定大小的哈希表
Hashtable(int size,float fillRatio)    //创建一个指定大小的哈希表,并且通过fillRatio指定填充比例。填充比例必须介于0.0和1.0之间,它决定了哈希表在重新调整大小之前的充满程度
Hashtable(Map m)    //创建一个以M中元素为初始化元素的哈希表。哈希表的容量被设置为M的两倍。

Hashtable中除了从Map接口中定义的方法外,还定义了以下方法:

序号方法描述
1void clear( )
 将此哈希表清空,使其不包含任何键。
2Object clone( )
创建此哈希表的浅表副本。
3boolean contains(Object value)
 测试此映射表中是否存在与指定值关联的键。
4boolean containsKey(Object key)
测试指定对象是否为此哈希表中的键。
5boolean containsValue(Object value)
如果此 Hashtable 将一个或多个键映射到此值,则返回 true。
6Enumeration elements( )
返回此哈希表中的值的枚举。
7Object get(Object key)
 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,则此方法返回 v;否则,返回 null。
8boolean isEmpty( )
测试此哈希表是否没有键映射到值。
9Enumeration keys( )
 返回此哈希表中的键的枚举。
10Object put(Object key, Object value)
将指定 key 映射到此哈希表中的指定 value。
11void rehash( )
增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。
12Object remove(Object key)
从哈希表中移除该键及其相应的值。
13int size( )
 返回此哈希表中的键的数量。
14String toString( )
返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 ", " (逗号加空格)分隔开的、括在括号中的一组条目。

package three;
 
import java.util.*;
 
public class myHashTable {
    public static void main(String args[]) {
          // Create a hash map
          Hashtable balance = new Hashtable();
          Enumeration names;
          String str;
          double bal;
 
          balance.put("Zara", new Double(3434.34));
          balance.put("Mahnaz", new Double(123.22));
          balance.put("Ayan", new Double(1378.00));
          balance.put("Daisy", new Double(99.22));
          balance.put("Qadir", new Double(-19.08));
 
          // Show all balances in hash table.
          names = balance.keys();
          while(names.hasMoreElements()) {
             str = (String) names.nextElement();
             System.out.println(str + ": " +
             balance.get(str));
          }
          System.out.println();
          // Deposit 1,000 into Zara's account
          bal = ((Double)balance.get("Zara")).doubleValue();
          balance.put("Zara", new Double(bal+1000));
          System.out.println("Zara's new balance: " +
          balance.get("Zara"));
       }
 
    /*输出结果
    Qadir: -19.08
    Zara: 3434.34
    Mahnaz: 123.22
    Daisy: 99.22
    Ayan: 1378.0
 
    Zara's new balance: 4434.34
     * */
}

practice

属性(Properties)

Properties 继承于 Hashtable.Properties 类表示了一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。

Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。

Properties 定义如下实例变量.这个变量持有一个Properties对象相关的默认属性列表。

Properties defaults;

Properties类定义了两个构造方法。

Properties()    //第一个构造方法没有默认值。
Properties(Properties propDefault)    //使用propDefault 作为默认值。
两种情况下,属性列表都为空

除了从Hashtable中所定义的方法,Properties定义了以下方法:

序号方法描述
1String getProperty(String key)
 用指定的键在此属性列表中搜索属性。
2String getProperty(String key, String defaultProperty)
用指定的键在属性列表中搜索属性。
3void list(PrintStream streamOut)
 将属性列表输出到指定的输出流。
4void list(PrintWriter streamOut)
将属性列表输出到指定的输出流。
5void load(InputStream streamIn) throws IOException
 从输入流中读取属性列表(键和元素对)。
6Enumeration propertyNames( )
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
7Object setProperty(String key, String value)
 调用 Hashtable 的方法 put。
8void store(OutputStream streamOut, String description)
 以适合使用  load(InputStream)方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
package three;
 
import java.util.*;
 
public class myProperties {
       public static void main(String args[]) {
          Properties capitals = new Properties();
          Set states;
          String str;
 
          capitals.put("Illinois", "Springfield");
          capitals.put("Missouri", "Jefferson City");
          capitals.put("Washington", "Olympia");
          capitals.put("California", "Sacramento");
          capitals.put("Indiana", "Indianapolis");
 
          // Show all states and capitals in hashtable.
          states = capitals.keySet(); // get set-view of keys
          Iterator itr = states.iterator();
          while(itr.hasNext()) {
             str = (String) itr.next();
             System.out.println("The capital of " +
                str + " is " + capitals.getProperty(str) + ".");
          }
          System.out.println();
 
          // look for state not in list -- specify default
          str = capitals.getProperty("Florida", "Not Found");
          System.out.println("The capital of Florida is "
              + str + ".");
       }
 
       /*输出结果
        * The capital of Missouri is Jefferson City.
        The capital of Illinois is Springfield.
        The capital of Indiana is Indianapolis.
        The capital of California is Sacramento.
        The capital of Washington is Olympia.
 
        The capital of Florida is Not Found.
        * */
}

ractice

三、泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型的好处

Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:

类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“String 列表”或者“String 到 String 的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException 展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。

消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程度,但是声明泛型变量会带来相应的啰嗦。

泛型方法

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

实例

下面的例子演示了如何使用泛型方法打印不同字符串的元素:

public class GenericMethodTest
{
   // 泛型方法 printArray
   public static < E > void printArray( E[] inputArray )
   {
      // 输出数组元素
         for ( E element : inputArray ){
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }
 
    public static void main( String args[] )
    {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
 
        System.out.println( "整型数组元素为:" );
        printArray( intArray  ); // 传递一个整型数组
 
        System.out.println( "\n双精度型数组元素为:" );
        printArray( doubleArray ); // 传递一个双精度型数组
 
        System.out.println( "\n字符型数组元素为:" );
        printArray( charArray ); // 传递一个字符型数组
    }
}
 
/*输出结果
整型数组元素为:
1 2 3 4 5 
 
双精度型数组元素为:
1.1 2.2 3.3 4.4 
 
字符型数组元素为:
H E L L O
* */

有界的类型参数:

可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。

要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。

下面的例子演示了"extends"如何使用在一般意义上的意思"extends"(类)或者"implements"(接口)。该例子中的泛型方法返回三个可比较对象的最大值。

public class MaximumTest
{
   // 比较三个值并返回最大值
   public static <T extends Comparable<T>> T maximum(T x, T y, T z)
   {
      T max = x; // 假设x是初始最大值
      if ( y.compareTo( max ) > 0 ){
         max = y; //y 更大
      }
      if ( z.compareTo( max ) > 0 ){
         max = z; // 现在 z 更大
      }
      return max; // 返回最大对象
   }
   public static void main( String args[] )
   {
      System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
                   3, 4, 5, maximum( 3, 4, 5 ) );
 
      System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
                   6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
 
      System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
         "apple", "orange", maximum( "pear", "apple", "orange" ) );
   }
}
 
/*输出结果
3, 4 和 5 中最大的数为 5
 
6.6, 8.8 和 7.7 中最大的数为 8.8
 
pear, apple 和 orange 中最大的数为 pear
*/

泛型类

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。

和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

如下实例演示了我们如何定义一个泛型类:

public class Box<T> {
 
  private T t;
 
  public void add(T t) {
    this.t = t;
  }
 
  public T get() {
    return t;
  }
 
  public static void main(String[] args) {
    Box<Integer> integerBox = new Box<Integer>();
    Box<String> stringBox = new Box<String>();
 
    integerBox.add(new Integer(10));
    stringBox.add(new String("嗨.."));
 
    System.out.printf("整型值为 :%d\n\n", integerBox.get());
    System.out.printf("字符串为 :%s\n", stringBox.get());
  }
}
/*
整型值为 :10
 
字符串为 :嗨..
*/

泛型类型通配符

类型通配符一般是使用?代替具体的类型参数

例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。

package three;
 
import java.util.ArrayList;
import java.util.List;
 
public class GenericTest {
     public static void main(String[] args) {
            List<String> name = new ArrayList<String>();
            List<Integer> age = new ArrayList<Integer>();
            List<Number> number = new ArrayList<Number>();
 
            name.add("nick");
            age.add(18);
            number.add(530);
 
            getData(name);
            getData(age);
            getData(number);
 
//            getUperNumber(name);    //报错
            getUperNumber(age);
            getUperNumber(number);
       }
 
       public static void getData(List<?> data) {
          System.out.println("getData :" + data.get(0));
       }
 
       public static void getUperNumber(List<? extends Number> data) {
              System.out.println("getUperNumber :" + data.get(0));
       }
}
 
/*输出结果
 * getData :nick
getData :18
getData :530
getUperNumber :18
getUperNumber :530
 * */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/13156.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java IO流_1

目录 分类 字节流 InputStream OutputStream 文件拷贝 字符流 FileReader FileWriter 处理流 BufferedReader BufferedWriter 文本拷贝 流是从起源到接受的有序数据&#xff0c;通过流的方式允许程序使用相同的方式来访问不同的输入/输出源。 分类 按数据…

4.26和4.27、selectAPI介绍(4.27、select代码)

4.26和4.27、selectAPI介绍&#xff08;4.27、select代码&#xff09; 1.selectAPI介绍①select多路复用流程图②select多路复用缺点 2.select代码使用介绍3.select代码实现①select服务端实现②select客户端实现 1.selectAPI介绍 主旨思想&#xff1a; 首先要构造一个关于文件…

echarts中横坐标显示为time,使用手册

需求&#xff1a; 后端传递&#xff08;两段数据&#xff0c;不同时间间隔&#xff09;的24h实时数据&#xff0c;前端需要根据24小时时间展示&#xff0c;要求&#xff1a;x轴为0-24h&#xff0c;每个两小时一个刻度 误区&#xff1a; 刚开始通过二维数据的形式秒点&#xff…

MySQL数据库从入门到精通学习第2天(创建数据库)

创建数据库 通过CREATE DATABASE语句来创建数据库通过CREATE SCHEMA语句来创建数据库通过IF NOT EXISTS进行判断创建 通过CREATE DATABASE语句来创建数据库 创建数据库的语法格式如下&#xff1a; CREATE DATABASE 【数据库名】; 创建数据库的库名跟标识符一样也是有要求的&…

设计模式-结构型模式之桥接模式

2. 桥接模式 2.1. 模式动机 设想如果要绘制矩形、圆形、椭圆、正方形&#xff0c;我们至少需要4个形状类&#xff0c;但是如果绘制的图形需要具有不同的颜色&#xff0c;如红色、绿色、蓝色等&#xff0c;此时至少有如下两种设计方案&#xff1a; 第一种设计方案是为每一种形状…

android sdl编译

SDL&#xff08;Simple DirectMedia Layer&#xff09;是一套开放源代码的跨平台多媒体开发库&#xff0c;使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数&#xff0c;让开发者只要用相同或是相似的代码就可以开发出跨多个平台。 1 下载SDL源码 http://www.libsd…

这篇把「精准测试」算是讲明白了

作为测试同学&#xff0c;我们经常在工作中会有这样的困惑&#xff1a;我写的用例真的有效且全面吗&#xff0c;我的测试真的做到有效覆盖了吗&#xff1f;回归阶段我到底需要回归什么&#xff0c;回归验证充分吗&#xff1f;这次的改动到底影响范围有多大&#xff1f;针对以上…

从编译器角度理解C++编译和连接原理

C编译链接整体介绍 链接主要工作 1 所有.o文件段的合并&#xff0c;符号表合并后&#xff0c;进行符号解析 链接时就是在符号表中找对应的符号是否只出现于.text或.data段一次&#xff0c;若一次都无&#xff0c;则符号未定义&#xff1b;若出现多次&#xff0c;符号重定义 符…

学习风`宇博客用户权限菜单模块

文章目录 用户-角色-菜单-资源 各表关系图菜单 和 路由菜单表及分析分析 /api/admin/user/menus接口MenuServiceImpl#listUserMenus接口返回示例及分析 前端代码分析menu.jsSideBar.vue 接口权限控制资源表 及 分析分析 WebSecurityConfig权限控制整体流程先说登录UserDetailsS…

行业那么多,为什么计算机领域这么火?

行业那么多&#xff0c;为什么计算机领域这么火&#xff1f; 计算机领域火已经不是一天两天了&#xff0c;从开始的进入互联网时代、到“互联网”、再到大数据、人工智能时代、数字化经济……计算机技术从行业内部的自我发展逐渐渗透到各行各业&#xff0c;甚至成为社会整体经济…

JVM-GC回收机制

目录 1.判定垃圾 1.引用计数 2.可达性分析 2.清理垃圾 1.标记清除 2.复制算法 3.标记整理 4.分代回收 上文讲述的Java运行时内存划分,对于程序计数器,虚拟机栈,本地方法栈来说,生命周期是和线程有关的,随着线程而生,随线程而灭,当方法结束或者线程结束时,它们的内存就自…

【Python_Scrapy学习笔记(十)】基于Scrapy框架的下载器中间件创建代理IP池

基于Scrapy框架的下载器中间件创建代理IP池 前言 本文中介绍 如何基于 Scrapy 框架的下载器中间件创建代理IP池。 正文 1、添加中间件的流程 在 middlewares.py 中新建 代理IP 中间件类在 settings.py 中添加此下载器中间件&#xff0c;设置优先级并开启 2、基于Scrapy框…

软件安全之CRC检测

CRC介绍 在玩某些游戏&#xff0c;例如fps类游戏时&#xff0c;你想要修改某些特定的数值实现一些功能&#xff0c;这时你很有可能会被查封账号甚至禁封机器码。因为你更改了游戏中的数据&#xff0c;从而导致接收方收到”错误的数据“。为尽量提高接收方收到数据的正确率&…

最新版本VSCode配置Python、PyQt5、QtDesigner环境并创建一个ui界面测试

参考链接&#xff1a;最新版本VSCode配置Python、PyQt5、QtDesigner环境并创建一个ui界面测试 一、安装Python3 PyQt5所支持的python版本是从3.5开始的&#xff0c;因此安装的Python3版本必须大于3.5。 我安装的位置是C:\Python\Python38。 参见真小白入门Pyhton的安装 二、安…

项目协同中的git

在远程代码仓库&#xff08;云效&#xff0c;gitee&#xff0c;github&#xff0c;Coding等&#xff09;新建一个代码库&#xff0c; 我使用的云效 新建一个develop分支&#xff0c;后续所有人的提交代码都合并到develop分支上面&#xff0c;一般develop分支是用来开发用的&…

NVM-无缝切换Node版本

NVM-无缝切换Node版本 如果未使用nvm之前已经下载了node&#xff0c;并且配置了环境变量,那么此时删除这些配置(Node的环境以及Node软件),使用nvm是为了在某些项目中使用低版本的node NVM下载 进入github的nvm readme&#xff1a; https://github.com/coreybutler/nvm-windows…

1007、1009:与进制问题、输出问题

1007 题目&#xff1a;本题要求计算A/B&#xff0c;其中A是不超过1000位的正整数&#xff0c;B是1位正整数。你需要输出商数Q和余数R&#xff0c;使得A B * Q R成立 思路&#xff1a;对于数字元素拆分&#xff0c;除法的计算方法用代码实现&#xff08;唯一一点就是在输出的…

【高危】Apache Spark 权限提升漏洞(CVE-2023-22946)

漏洞描述 Apache Spark 是一款支持非循环数据流和内存计算的大规模数据处理引擎。 使用 spark-submit 脚本在集群中启动任务可以通过指定proxy-user参数限制运行用户。在 Apache Spark 受影响版本中&#xff0c;攻击者通过指定自定义的classpath&#xff0c;则可以覆盖该配置…

homeassistant配置MQTT集成以及传感器实体(STM32连接进入homeassistant)

大家可以看作者的小破站教学视频&#xff08;如果喜欢的话可以点个关注&#xff0c;给个三联&#xff01;啊哈哈哈哈哈哈&#xff09;&#xff1a; 【homeassistant配置MQTT集成以及传感器实体&#xff08;STM32连接进入homeassistant&#xff09;】 最近homeassistan更新之后…

Python ---->> PiP 的重要性

我的个人博客主页&#xff1a;如果’真能转义1️⃣说1️⃣的博客主页 关于Python基本语法学习---->可以参考我的这篇博客&#xff1a;《我在VScode学Python》 Python是一种跨平台的计算机程序设计语言&#xff0c;是一个高层次的结合了解释性、编译性、互动性和面向对象的语…