我们知道文件存储可以存储一些数据,我们现在想要利用文件存储的方法, * 来构建一类类似于redis的持久化存储类。
* 它可以存储不同类型的对象,并且可以设置过期时间,
* 当过期时间到达时,对象会被自动删除或不可访问。
* 注意,这里的存储对象期望可以是尽可能支持广泛类型的对象, 而不仅仅是特定的类型的对象。 实现以下问题的方法很多,并没有唯一答案, 我们重点关注代码的可读性和可维护性及思路。
package com.yupi.autoreply.monitor;
import lombok.ToString;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* 面试题:我们知道文件存储可以存储一些数据,我们现在想要利用文件存储的方法,
* 来构建一类类似于redis的持久化存储类。
* 它可以存储不同类型的对象,并且可以设置过期时间,
* 当过期时间到达时,对象会被自动删除或不可访问。
* 注意,这里的存储对象期望可以是尽可能支持广泛类型的对象,
* 而不仅仅是特定的类型的对象。
* 提示:实现以下问题的方法很多,并没有唯一答案,请尽可能提供简洁的实现。
* 我们重点关注代码的可读性和可维护性及思路。
* 提交格式:请提供实现的代码,并且提供运行结果的截图。
*/
public class DataSave {
// 存储key-value对应关系的Map
private Map<String, Long> keysExpireTimeMap = new HashMap<>();
private Map<String, Serializable> keyValuesMap = new HashMap<>();
// 文件路径
private static final String FILE_PATH = "data_save_file.dat";
/**
* 请实现持久化存储函数(使用文件存储相关方法)
*
* @param key 存储的key
* @param s 存储的对象
* @param expire 过期时间,单位秒,如果为0则表示永不过期
*/
void save(String key, Serializable s, int expire) {
// 存储key-value对应关系
keyValuesMap.put(key, s);
// 设置过期时间
if (expire > 0) {
long expireTime = System.currentTimeMillis() + expire * 1000;
keysExpireTimeMap.put(key, expireTime);
}
// 将key-value对应关系保存到文件中
saveToFile();
}
/**
* 请实现持久化数据的取出
*
* @param key 存储的key
* @return 存储的对象
*/
Object load(String key) {
Serializable value = keyValuesMap.get(key);
// 当value为空或者key已经过期时,返回null
if (value == null || (keysExpireTimeMap.containsKey(key) &&
keysExpireTimeMap.get(key) < System.currentTimeMillis())) {
return null;
}
return value;
}
/**
* 将key-values对应关系存储到文件中
*/
private void saveToFile() {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(FILE_PATH))) {
out.writeObject(keyValuesMap);
out.writeObject(keysExpireTimeMap);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从文件中加载key-values对应关系
*/
@SuppressWarnings("unchecked")
private void loadFromFile() {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(FILE_PATH))) {
keyValuesMap = (Map<String, Serializable>) in.readObject();
keysExpireTimeMap = (Map<String, Long>) in.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 初始化并加载数据
DataSave dataSave = new DataSave();
dataSave.loadFromFile();
School sc = new School("wuhan", "wuhan location");
Clazz c = new Clazz("1", 30, 2, sc);
Student s = new Student("zhangsan", 18, c);
Student s0 = new Student("lisi", 22, c);
// 存储和取出学生对象
dataSave.save("student", s, 0);
Student s2 = (Student) dataSave.load("student");
if (s2 != null) {
System.out.println("age:" + s2.age);
System.out.println("grade:" + s2.clazz.grade);
System.out.println("address:" + s2.clazz.school.address);
}
// 存储和取出班级对象
dataSave.save("clazz", c, 0);
Clazz c2 = (Clazz) dataSave.load("clazz");
if (c2 != null) {
System.out.println("grade:" + c2.grade);
System.out.println("address:" + c2.school.address);
}
// 存储和取出学校对象
dataSave.save("school", sc, 0);
School sc2 = (School) dataSave.load("school");
if (sc2 != null) {
System.out.println("address:" + sc2.address);
}
// 存储和取出学生列表
ArrayList<Student> students = new ArrayList<>();
students.add(s);
students.add(s0);
dataSave.save("students", students, 0);
ArrayList students2 = (ArrayList) (dataSave.load("students"));
if (students2 != null) {
System.out.println("students size:" + students2.size());
System.out.println("students1 age:" + ((Student) students2.get(0)).age);
}
// 存储和取出学生对象,过期时间为10秒
dataSave.save("school_test", sc, 10);
School sc3 = (School) (dataSave.load("school_test"));
if (sc3 != null) {
System.out.println("未过期时,school:" + sc3);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
School sc4 = (School) (dataSave.load("school_test"));
System.out.println("已过期时,school:" + (sc4 == null));
}
}
@ToString
class Student implements Serializable {
String name;
int age;
Clazz clazz;
public Student(String name, int age, Clazz clazz) {
this.name = name;
this.age = age;
this.clazz = clazz;
}
}
@ToString
class Clazz implements Serializable {
String grade;
int studentNumbers;
int teacherNumbers;
School school;
public Clazz(String grade, int studentNumbers, int teacherNumbers, School school) {
this.grade = grade;
this.studentNumbers = studentNumbers;
this.teacherNumbers = teacherNumbers;
this.school = school;
}
}
@ToString
class School implements Serializable {
String name;
String address;
public School(String name, String address) {
this.name = name;
this.address = address;
}
}