Hashtable、Map.Entry、自定义key、Stack、Properties、Collections
目录
Hashtable
Hashtable的key和value都不允许为null,为null会报NullPointerException。
示例:
public class TestHashtable {
public static void main(String[] args) {
Map<String,String> map = new Hashtable<>();
map.put("1","one");
map.put("2","two");
map.put("3","three");
map.put("null",null);
map.put("4","four");
System.out.println(map);
}
}
结果:
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Hashtable.put(Hashtable.java:475)
at com.tx.map.TestHashtable.main(TestHashtable.java:17)
hashtable扩容:
int newCapacity = (oldCapacity << 1) + 1; //hashtable扩容
Hashtable和HashMap的区别:
1、Hashtable的key和value不运行为null,HashMap的key和value可以为null。
2、HashMap的初始容量为0,第一次使用put()是容量增加为16,Hashtable无参构造容量默认为11。
3、HashMap和hashtable的阈值都为75%,超过自动增加,但HashMap每次扩容翻1倍(oldCap << 1),Hashtable扩容翻1倍加1((oldCap << 1) + 1)。
4、HashMap在存入8个数据之后转为红黑树,Hashtable不会转变为红黑树。
5、HashMap使用线程异步处理,属于非线程安全,Hashtable使用synchronized进行线程同步处理,属于线程安全。
Map.Entry
Map.Entry是Map的一个内部接口,可以使用getKey()和getValue()来获取key的值和value的值。
示例:
public class TestMapEntry {
public static void main(String[] args) throws IOException {
Map<String, String> map = new HashMap<>(20);
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
map.put("4", "four");
map.put("5", "five");
System.out.println(map.get("5"));
System.out.println();
System.out.println(map);
System.out.println();
long time = getKeyForeach(map);
System.out.println("耗时 ->"+time);
System.out.println();
//Map使用entrySet转换为Set调用iterator使用Iterator进行输出
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
long data = getKey(iterator);
System.out.println("耗时 ->"+data);
}
/**
* 迭代输出Map.Entry内存储的值
* 数据多时,用while
* @param iterator Iterator实例
*/
private static long getKey(Iterator<Map.Entry<String, String>> iterator) {
long timeA = System.currentTimeMillis();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println("key() ->" + entry.getKey() + "、Value() ->" + entry.getValue());
}
long timeB = System.currentTimeMillis();
return timeB - timeA;
}
/**
* foreach循环输出Map.Entry内存储的值
* 耗时比while多20倍
* @param map map的实例
*/
private static long getKeyForeach(Map<String, String> map) {
long timeA = System.currentTimeMillis();
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key ->" + entry.getKey() + "、value ->" + entry.getValue());
}
long timeB = System.currentTimeMillis();
return timeB - timeA;
}
}
结果:
five
{1=one, 2=two, 3=three, 4=four, 5=five}
key ->1、value ->one
key ->2、value ->two
key ->3、value ->three
key ->4、value ->four
key ->5、value ->five
耗时 ->23
key() ->1、Value() ->one
key() ->2、Value() ->two
key() ->3、Value() ->three
key() ->4、Value() ->four
key() ->5、Value() ->five
耗时 ->0
自定义Key
1、使用对象做key时,需要重写HashCode()和equals()获取哈希码,来进行对象比较。
2、因为哈希码是数字,使用哈希码进行比较时,比较的速度更快。
3、发现哈希码相同才会进行内容的比较。
在未重写的情况下:
public class TestTargetKey {
public static void main(String[] args) {
Map<Ball,String> map = new HashMap<>(16);
map.put(new Ball("篮球",155.5),"1");
System.out.println(map.get(new Ball("篮球",155.5)));
}
}
class Ball{
private String name;
private double price;
public Ball(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Ball{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
结果:
null
在重写的情况下:
public class TestTargetKey {
public static void main(String[] args) {
Map<Ball,String> map = new HashMap<>(16);
map.put(new Ball("篮球",155.5),"1");
System.out.println(map.get(new Ball("篮球",155.5)));
}
}
class Ball{
private String name;
private double price;
public Ball(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Ball{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Ball ball = (Ball) o;
return Double.compare(ball.price, price) == 0 &&
Objects.equals(name, ball.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
}
结果:
1
当哈希码相同(哈希冲突)时,解决方法有四个(开放定址法、链地址法、再哈希法、建立公共的溢出区),Java使用链地址法,将相同哈希码的数据,使用链表的形式进行存储,查找时,再使用内容的比较。
Stack
Stack是Vector的子类,Stack栈的操作先入后出。
入栈:
出栈:
常用方法:
方法 | 说明 |
---|---|
public E push(E item) | 向栈中增加数据 |
public synchronized E pop() | 弹出数据(先进后出) |
public boolean empty() | 判断栈中是否存在数据 |
示例:
public class TestStack {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
stack.push("5");
stack.push("6");
stack.push("7");
stack.push("8");
while(!stack.empty()){ //空栈判断,当栈为空仍进行pop输出时,会报出EmptyStackException
System.out.print(stack.pop()+"、");
}
}
}
结果:
8、7、6、5、4、3、2、1、
当栈中数据为空使用pop时:
Exception in thread "main" java.util.EmptyStackException
Properties
常用方法:
方法 | 说明 |
---|---|
public Properties() { this((Properties)null, 8); } | Properties的无参构造,默认的容量为8 |
public synchronized Object setProperty(String key, String value) | 设置属性的key和value值 |
public String getProperty(String key) | 获取属性,key不存在输出null |
public String getProperty(String key, String defaultValue) | 获取属性,不存在key则输出defaultValue |
public void list(PrintStream out) | 列出全部属性 |
public void list(PrintWriter out) | 列出全部属性 |
public void store(Writer writer, String comments) throws IOException | 向字符输出流输出全部属性 |
public void store(OutputStream out, String comments) throws IOException | 向字节输出流输出全部属性 |
public synchronized void load(InputStream inStream) throws IOException | 从字节输入流读取数据 |
public synchronized void load(Reader reader) throws IOException | 从字符输入流读取数据 |
示例:
public class TestProperties {
public static void main(String[] args) throws IOException {
//PrintWriter的实例
PrintWriter printWriter = new PrintWriter("D:" + File.separator + "TestFour.properties");
//PrintStream的实例
PrintStream printStream = new PrintStream("D:" + File.separator + "TestThree.properties");
//Properties的实例
Properties properties = new Properties();
//setProperty():增加数据
properties.setProperty("1", "one");
properties.setProperty("2", "two");
properties.setProperty("3", "three");
properties.setProperty("4", "four");
properties.setProperty("5", "five");
//输出properties
System.out.println(properties);
//getProperties():根据key获取value值
System.out.println(properties.getProperty("1"));
//getProperties():根据key获取value值,key不存在返回null
System.out.println(properties.getProperty("6"));
//getProperties():根据key获取value值,key不存在返回自定义设置的defaultValue值
System.out.println(properties.getProperty("6", "value不存在数据"));
//store():将数据存入指定指定文件内,输入注释内容
properties.store(new FileOutputStream("D:" + File.separator + "TestOne.properties", true), "Properties输出测试");
//store():将数据存入指定指定文件内,输入注释内容
properties.store(new FileWriter("D:" + File.separator + "TestTwo.properties", true), "Properties输出测试");
//list():在指定的文件处,打印数据
properties.list(printStream);
//list():在指定的文件处,打印数据
properties.list(printWriter);
//将指定文件的数据输入到properties内
properties.load(new FileInputStream("D:" + File.separator + "TestOne.properties"));
//将指定文件的数据输入到properties内
properties.load(new FileReader("D:" + File.separator + "TestTwo.properties"));
//在将指定文件输入后,可以利用文件内数据的key获取value值
System.out.println(properties.getProperty("3"));
printStream.close();
printWriter.close();
}
}
结果:
{1=one, 2=two, 3=three, 4=four, 5=five}
one
null
value不存在数据
three
Collections
用来弥补传统类集的设计不足。
示例:
public class TestCollections {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list,"5","2","1","4","3");
Collections.sort(list);
System.out.println(list);
System.out.println(Collections.binarySearch(list,"3"));
}
}
结果:
[1, 2, 3, 4, 5]
2