Java八股系列——Java数据结构

本文详细介绍了Java集合框架中的几个经典类和接口,包括Enumeration的迭代功能,BitSet的位操作特性,Vector的线程安全和动态扩展,Stack的基本操作,Dictionary作为键值对存储的抽象类,以及Hashtable的同步特性和HashMap的区别。这些内容展示了Java早期集合框架的基础和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果有兴趣了解更多相关内容,欢迎来我的个人网站看看:瞳孔空间

一:Enumeration

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

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

public interface Enumeration<E> {
    /**
     * 判断是否为空
     */
    boolean hasMoreElements();

    /**
     * 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
     * 否则抛出NoSuchElementException异常。
     */
    E nextElement();
}

Enumeration只是接口,具体使用还得靠实现类,下面是使用示例

public class Test1 {
    public static void main(String[] args) {
        Enumeration<String> days;
        Vector<String> 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());
        }
    }
}

这里采用的是Vector的elements方法返回的实现类,通过源码我们可以看到,是采用匿名内部类实现的,count就是指针,每次执行nextElement方法后指针后移,以此打印全部数据。

	protected Object[] elementData;

    E elementData(int index) {
        return (E) elementData[index];
    }

    public Enumeration<E> elements() {
        return new Enumeration<E>() {
            int count = 0;

            public boolean hasMoreElements() {
                return count < elementCount;
            }

            public E nextElement() {
                synchronized (Vector.this) {
                    if (count < elementCount) {
                        return elementData(count++);
                    }
                }
                throw new NoSuchElementException("Vector Enumeration");
            }
        };
    }

二:BitSet

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

BitSet定义了两个构造方法:


    /**
     * 无参构造,初始
     */
    public BitSet() {
        initWords(BITS_PER_WORD);
        sizeIsSticky = false;
    }

    /**
     * 允许用户指定初始大小。所有位初始化为0
     */
    public BitSet(int nbits) {
        // nbits can't be negative; size 0 is OK
        if (nbits < 0)
            throw new NegativeArraySizeException("nbits < 0: " + nbits);

        initWords(nbits);
        sizeIsSticky = true;
    }

下面的程序说明这个集合所支持的几种方法:

public class Test1 {
    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);
        System.out.println("\nInitial pattern in bits2: ");
        System.out.println(bits2);

        // AND bits
        bits2.and(bits1);
        System.out.println("\nbits2 AND bits1: ");
        System.out.println(bits2);

        // OR bits
        bits2.or(bits1);
        System.out.println("\nbits2 OR bits1: ");
        System.out.println(bits2);

        // XOR bits
        bits2.xor(bits1);
        System.out.println("\nbits2 XOR bits1: ");
        System.out.println(bits2);
    }
}

三:Vector

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

  • ArrayList不是线程安全的,Vector在关键方法上都加了synchronized,是线程安全的
  • ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。

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

Vector 类支持 4 种构造方法:

	// 创建指定大小的向量,并且增量用 incr 指定。增量表示向量每次增加的元素数目
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

	// 创建指定大小的向量
	public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
    
    // 创建一个默认的向量,默认大小为 10
	public Vector() {
        this(10);
    }
    
    // 创建一个包含集合 c 元素的向量
    public Vector(Collection<? extends E> c) {
        Object[] a = c.toArray();
        elementCount = a.length;
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
            elementData = Arrays.copyOf(a, elementCount, Object[].class);
        }
    }

下面的程序说明这个集合所支持的几种方法:

public class Test1 {
    public static void main(String[] args) {
        // initial size is 3, increment is 2
        Vector v = new Vector(3, 2);
        System.out.println("Initial size: " + v.size());
        System.out.println("Initial capacity: " +
                v.capacity());
        v.addElement(1);
        v.addElement(2);
        v.addElement(3);
        v.addElement(4);
        System.out.println("Capacity after four additions: " +
                v.capacity());

        v.addElement(5.45);
        System.out.println("Current capacity: " +
                v.capacity());
        v.addElement(6.08);
        v.addElement(7);
        System.out.println("Current capacity: " +
                v.capacity());
        v.addElement((float) 9.4);
        v.addElement(10);
        System.out.println("Current capacity: " +
                v.capacity());
        v.addElement(11);
        v.addElement(12);
        System.out.println("First element: " +
                (Integer)v.firstElement());
        System.out.println("Last element: " +
                (Integer)v.lastElement());
        if(v.contains(3))
            System.out.println("Vector contains 3.");
        // enumerate the elements in the vector.
        Enumeration vEnum = v.elements();
        System.out.println("\nElements in vector:");
        while(vEnum.hasMoreElements())
            System.out.print(vEnum.nextElement() + " ");
        System.out.println();
    }
}

四:Stack

感觉没什么好说的

五:Dictionary

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

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

不过Dictionary类已经过时了。在实际开发中,可以实现Map接口来获取键/值的存储功能。

public abstract
class Dictionary<K,V> {

    public Dictionary() {
    }

    /**
     * 返回字典中键值对的数量
     */
    abstract public int size();

    /**
     * 判断此 dictionary 是否为空
     */
    abstract public boolean isEmpty();

    /**
     * 返回此 dictionary 中的键的枚举
     */
    abstract public Enumeration<K> keys();

    /**
     * 返回此 dictionary 中值的枚举
     */
    abstract public Enumeration<V> elements();

    /**
     * 返回此 dictionary 中该键所映射到的值
     */
    abstract public V get(Object key);

    /**
     * 将指定 key 映射到此 dictionary 中指定 value。
     */
    abstract public V put(K key, V value);

    /**
     * 从此 dictionary 中移除 key (及其相应的 value)
     */
    abstract public V remove(Object key);
}

六:Hashtable

Hashtable是原始的java.util的一部分, 是一个Dictionary具体的实现 。然而,Java 2 重构的Hashtable又实现了Map接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步。

像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。然后,该键经过哈希处理,所得到的散列码被用作存储在该表中值的索引。

以下是使用示例:

public class Test1 {
    public static void main(String[] args) {
        // Create a hash map
        Hashtable<String, Double> balance = new Hashtable<>();
        Enumeration<String> names;
        String str;
        double bal;

        balance.put("Zara", 3434.34);
        balance.put("Mahnaz", 123.22);
        balance.put("Ayan", 1378.00);
        balance.put("Daisy", 99.22);
        balance.put("Qadir", -19.08);

        // Show all balances in hash table.
        names = balance.keys();
        while(names.hasMoreElements()) {
            str = names.nextElement();
            System.out.println(str + ": " + balance.get(str));
        }
        // Deposit 1,000 into Zara's account
        bal = balance.get("Zara");
        balance.put("Zara", bal + 1000);
        System.out.println("\nZara's new balance: " + balance.get("Zara"));
    }
}

Hashtable 和 HashMap 的区别:

  • 线程安全性不同。HashMap线程不安全;Hashtable 中的方法是Synchronize的。
  • key、value是否允许null。HashMap的key和value都是可以是null,key只允许一个null;Hashtable的key和value都不可为null。
  • 迭代器不同。HashMap的Iterator是fail-fast迭代器;Hashtable还使用了enumerator迭代器。
  • hash的计算方式不同。HashMap计算了hash值;Hashtable使用了key的hashCode方法。
  • 默认初始大小和扩容方式不同。HashMap默认初始大小16,容量必须是2的整数次幂,扩容时将容量变为原来的2倍;Hashtable默认初始大小11,扩容时将容量变为原来的2倍加1。
  • 是否有contains方法。HashMap没有contains方法;Hashtable包含contains方法,类似于containsValue。
  • 父类不同。HashMap继承自AbstractMap;Hashtable继承自Dictionary。

七:Properties

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

除了从 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 表中的属性列表(键和元素对)写入输出流。

使用示例如下:

public class Test1 {
    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) + ".");
        }
        // look for state not in list -- specify default
        str = capitals.getProperty("Florida", "Not Found");
        System.out.println("\nThe capital of Florida is " + str + ".");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值