18、Java中的 数据结构
,Java工具包中提供了强大的数据结构,他大致分为:
1. 枚举 (Enumeration)
2. 位集合 (BitSet)
3. 向量 (Vector)
4. 栈 (Stack)
5. 字典 (Dictionary)
6. 哈希表 (Hashtable)
7. 属性 (Properties)
在Java1就已经有了这七个数据结构,是不是很酷, 在Java2中引入了新的数据结构 集合框架 Collection,下一节再谈论(非常重要,面试也常问).
1、枚举 (Enumeration)
1.1 Enumeration
源码:
public interface Enumeration<E> {
boolean hasMoreElements();
E nextElement();
}
Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素。
这种传统接口已被迭代器取代,虽然Enumeration 还未被遗弃,但在现代代码中已经被很少使用了。尽管如此,它还是使用在诸如Vector和Properties这些传统类所定义的方法中
实例1 :
import java.util.Vector;
import java.util.Enumeration;
public class EnumerationTester {
public static void main(String args[]) {
Enumeration<String> days;
Vector<String> dayNames = new Vector<String>();
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());
}
}
}
以上实例编译运行结果如下:
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
实例2:
{
Map map = request.getParameterMap();
java.util.Enumeration enum=this.getRequest().getParameterNames();
while ( enum.hasMoreElements()){
String paramName = (String) enum.nextElement();
String[] values = request.getParameterValues(paramName);
for (int i = 0; i < values.length; i++) {
System.out.println("[" + i + "] " + paramName + " " + values[i]);
}
}
//形成键值对应的map
map.put(paramName, paramValue);
}
1.2 枚举类
Java中的枚举其实是一种语法糖,在 JDK 1.5之后出现,用来表示固定且有限个的对象。比如一个季节类有春、夏、秋、冬四个对象;一个星期有星期一到星期日七个对象。这些明显都是固定的,且有限个。
枚举类和普通类的区别
①、使用 enum 定义的枚举类默认继承 java.lang.Enum 类,即枚举类是不能再继承别的类了。而普通类的一般父类默认是 Object
②、枚举类的构造器只能使用 private 定义,而普通类的还可以用 public 修饰
③、枚举类的所有实例必须在枚举类中显示列出(,分隔 ;结尾),列出的实例系统会默认自动添加 public static final 修饰
④、所有的枚举类都提供了一个 values() 方法,可以用来遍历枚举值
实例:
package cn.fage.enums;
/**
* @author lin
* @version 1.0
* @date 2020-06-19 17:11
* @Description TODO
*/
public enum SeasonTwoArgs {
/**
* 春天
*/
SPRING(1, "春天"),
SUMMER(2, "夏天"),
AUTUMN(3, "秋天"),
WINTER(4, "冬天");
int key;
String msg;
SeasonTwoArgs(int key, String season) {
this.key = key;
this.msg = season;
System.out.println("初始化:" + this.name() + "," + this.msg + "," + season);
}
// 很多情况,我们可能从前端拿到的值是枚举类的 key ,然后就可以通过以下静态方法获取到对应枚举值
public static SeasonTwoArgs valueofKey(Integer key) {
for (SeasonTwoArgs season : SeasonTwoArgs.values()) {
if (season.key == key) {
return season;
}
}
throw new IllegalArgumentException("No element matches " + key);
}
public String getMsg() {
return msg;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public void setMsg(String msg) {
this.msg = msg;
}
public static void main(String[] args) {
SeasonTwoArgs autumn = SeasonTwoArgs.AUTUMN;
System.out.println("autumn.getKey() = " + autumn.getKey());
System.out.println("autumn.getMsg() = " + autumn.getMsg());
System.out.println("autumn = " + autumn);
}
}
运行结果如下所示:
初始化:SPRING,春天,春天
初始化:SUMMER,夏天,夏天
初始化:AUTUMN,秋天,秋天
初始化:WINTER,冬天,冬天
autumn.getKey() = 3
autumn.getMsg() = 秋天
autumn = AUTUMN
枚举类是最完美的单例模式
2、位集合 (BitSet)
一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。这和位向量(vector of bits)比较类似。
这是一个传统的类,但它在Java 2中被完全重新设计。
BitSet定义了两个构造方法。
第一个构造方法创建一个默认的对象:
BitSet()
第二个方法允许用户指定初始大小。所有位初始化为0。
BitSet(int size)
实例:
package cn.fage.three;
import java.util.BitSet;
/**
* @author lin
* @version 1.0
* @date 2020-07-10 14:00
* @Description TODO
*/
public class BitSetDemo {
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("bits1.length() = " + bits1.length());
System.out.println("bits2.length() = " + bits2.length());
System.out.println("bits1.get(4) = " + bits1.get(0));
System.out.println("bits2.get(4) = " + bits2.get(0));
System.out.println("bits1 = " + bits1);
System.out.println("bits2 = " + bits2);
// void and(BitSet set)
// 对此目标位 set 和参数位 set 执行逻辑与操作, (最大位)
// bits2.and(bits1);
// System.out.println(bits1);
// System.out.println(bits2);
// void andNot(BitSet set)
// 清除此 BitSet 中所有的位,其相应的位在指定的 BitSet 中已设置 (去重)
// bits2.andNot(bits1);
// System.out.println(bits1);
// System.out.println(bits2);
//int cardinality( )
//返回此 BitSet 中设置为 true 的位数
// System.out.println(bits1.cardinality());
// System.out.println(bits2.cardinality());
//void clear( )
//将此 BitSet 中的所有位设置为 false
// bits1.clear();
// System.out.println(bits1);
// System.out.println(bits2);
// void clear(int index)
// 将索引指定处的位设置为 false
// bits1.clear(2);
// System.out.println(bits1);
// System.out.println(bits2);
// void clear(int startIndex, int endIndex)
// 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 false
//前开后闭
// bits1.clear(2,6);
// System.out.println(bits1);
// System.out.println(bits2);
// Object clone( )
// 复制此 BitSet,生成一个与之相等的新 BitSet
//boolean equals(Object bitSet)
// 将此对象与指定的对象进行比较
// BitSet bits3 = (BitSet) bits1.clone();
// System.out.println(bits3);
// System.out.println(bits3.equals(bits1));
//void flip(int index)
// 将指定索引处的位设置为其当前值的补码
// bits1.flip(0);
// bits1.flip(2);
// bits1.flip(3);
// System.out.println(bits1);
// System.out.println(bits2);
//boolean get(int index)
// 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的每个位设置为其当前值的补码
// 返回指定索引处的位值
// System.out.println(bits1.get(4));
// System.out.println(bits1.get(5));
//BitSet get(int startIndex, int endIndex)
// 返回一个新的 BitSet,它由此 BitSet 中从 fromIndex(包括)到 toIndex(不包括)范围内的位组成
// BitSet bits3=bits1.get(2,6);
// System.out.println(bits3);
//int hashCode( )
// 返回此位 set 的哈希码值
// System.out.println(bits1.hashCode());
// System.out.println(bits1.hashCode());
//boolean intersects(BitSet bitSet)
// 如果指定的 BitSet 中有设置为 true 的位,并且在此 BitSet 中也将其设置为 true,则返回 true
/*BitSet bits3 = new BitSet(16);
System.out.println(bits3);
bits3.set(0);
System.out.println(bits3.intersects(bits1));
System.out.println(bits3.intersects(bits2));
System.out.println(bits1);
System.out.println(bits2);
System.out.println(bits3);*/
//boolean isEmpty( )
// 如果此 BitSet 中没有包含任何设置为 true 的位,则返回 true
// bits1.clear();
// System.out.println(bits1);
// System.out.println(bits1.isEmpty());
//...
//OR bits
// 对此位 set 和位 set 参数执行逻辑或操作
// bits2.or(bits1);
// System.out.println("bits2 OR bits1: ");
// System.out.println(bits2);
//返回此 BitSet 表示位值时实际使用空间的位数
// System.out.println(bits1.size());
// System.out.println(bits1.toString());
// 对此位 set 和位 set 参数执行逻辑异或操作
// bits1.xor(bits2);
// System.out.println(bits1);
}
}
3、向量 (Vector)
Vector(向量)是 java.util 包中的一个类,该类实现了类似动态数组的功能。
向量和数组相似,都可以保存一组数据(数据列表)。但是数组的大小是固定的,一旦指定,就不能改变,而向量却提供了一种类似于“动态数组”的功能,向量与数组的重要区别之一就是向量的容量是可变的。
构造方法:
1 创建一个默认的向量,默认大小为 10:
Vector()
2 创建指定大小的向量。
Vector(int size)
3 创建指定大小的向量,并且增量用 incr 指定。增量表示向量每次增加的元素数目。
Vector(int size,int incr)
4 创建一个包含集合 c 元素的向量:
Vector(Collection c)
实例:
package cn.fage.three;
import java.util.Enumeration;
import java.util.Vector;
/**
* @author lin
* @version 1.0
* @date 2020-07-10 14:57
* @Description TODO
*/
public class TestVectorDemo {
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(new Integer(1));
v.addElement(new Integer(2));
v.addElement(new Integer(3));
v.addElement(new Integer(4));
System.out.println("Capacity after four additions: " +
v.capacity());
v.addElement(new Double(5.45));
System.out.println("Current capacity: " +
v.capacity());
v.addElement(new Double(6.08));
v.addElement(new Integer(7));
System.out.println("Current capacity: " +
v.capacity());
v.addElement(new Float(9.4));
v.addElement(new Integer(10));
System.out.println("Current capacity: " +
v.capacity());
v.addElement(new Integer(11));
v.addElement(new Integer(12));
System.out.println("First element: " +
(Integer) v.firstElement());
System.out.println("Last element: " +
(Integer) v.lastElement());
if (v.contains(new Integer(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();
}
}
以上运行如下所示:
Initial size: 0
Initial capacity: 3
Capacity after four additions: 5
Current capacity: 5
Current capacity: 7
Current capacity: 9
First element: 1
Last element: 12
Vector contains 3.
Elements in vector:
1 2 3 4 5.45 6.08 7 9.4 10 11 12
4、栈 (Stack)
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
堆栈只定义了默认构造函数,用来创建一个空栈。堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
Stack()
1.栈(Stack)的介绍
栈是一个先入后出(FILO:First In Last Out)的有序列表。
栈(Stack)是限制线性表中元素的插入和删除只能在同一端进行的一种特殊线性表。
允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶
而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
实例:
package cn.fage.three;
import java.util.EmptyStackException;
import java.util.Stack;
/**
* @author lin
* @version 1.0
* @date 2020-07-10 15:00
* @Description TODO
*/
public class TestStackDemo {
static void showpush(Stack<Integer> st, int a) {
st.push(new Integer(a));
System.out.println("push(" + a + ")");
System.out.println("stack: " + st);
}
static void showpop(Stack<Integer> 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<Integer> st = new Stack<Integer>();
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: []
5、字典 (Dictionary)
Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。
给出键和值,你就可以将值存储在Dictionary对象中。一旦该值被存储,就可以通过它的键来获取它。所以和Map一样, Dictionary 也可以作为一个键/值对列表。
Dictionary类已经过时了。在实际开发中,你可以[实现Map接口来获取键/值的存储功能。
6、哈希表 (Hashtable)
public class HashTableDemo {
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
7、属性 (Properties)
java.util.Properties 继承于 Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时, System.getProperties 方法就是返回一个 Properties 对象。
特点:
Properties类是Hashtable的子类,所以Map集合中的方法都可以使用。
Properties集合是没有泛型的,所有的key和value值都是字符串。
有和流技术结合的方法,是唯一可以和IO流结合的集合类,当与流结合时可以永久存储数据,其他集合只能暂时存储。
Properties与别的集合的区别是它能保存到流里或者在流中加载,属性列表的每一个键和值都是字符串。
常用方法
添加/修改
setProperty(String key,String value);
getProperty(String key)
在这个属性列表中搜索指定的键的属性。
load(InputStream inStream)
从输入字节流中读取属性列表(键和元素对)。
load(Reader reader)
新建一个test.txt文件.
name=张三
age=18
county=杭州
package FileAndIO;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
//创建properties对象和文件输入流对象
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("Demo//test.txt");
//用load方法传入输入流对象
properties.load(fileInputStream);
//用stringPropertyNames方法获取所有key,存入set集合中
Set<String> keys = properties.stringPropertyNames();
//遍历set集合,打印获取到的键值对
for (String key : keys) {
System.out.println(key+":"+properties.getProperty(key));
}
}
}
发哥讲