Skip to content

配置序列化与遍历 ​

配置 API 能直接存基本类型和 String、List。但自定义对象(如你写的 Person 类)直接 set 存不进去——要靠序列化。

哪些类型能直接 set ​

所有 getXxx 方法对应的类型都能直接存(int、String、List<String> 等)。还有一些 Bukkit 类型(如 ItemStack)也能直接存——判断标准是看 JavaDoc 里它是否实现了 ConfigurationSerializable。

自定义类型默认不能直接存:

java
Person person = new Person("tdiant", "hello!!");
getConfig().set("demo", person);
getConfig().get("demo"); // 拿不回来,存了个寂寞

序列化自定义类型 ​

让自定义类实现 ConfigurationSerializable,提供 serialize() 和 deserialize():

java
public class Person implements ConfigurationSerializable {
    public String name;
    public String introduction;

    public Person(String name, String introduction) {
        this.name = name;
        this.introduction = introduction;
    }

    // 序列化:把对象转成 Map 存进配置
    @Override
    public Map<String, Object> serialize() {
        Map<String, Object> map = new HashMap<>();
        map.put("name", name);
        map.put("introduction", introduction);
        return map;
    }

    // 反序列化:从 Map 还原对象
    public static Person deserialize(Map<String, Object> map) {
        return new Person(
            (String) map.get("name"),
            (String) map.get("introduction")
        );
    }
}

全限定类名会被记录

序列化后配置里会自动写入这个对象的完整类名,反序列化时按它找类。所以改包名/类名会导致旧配置无法反序列化。

现在能直接存取了:

java
Person person = new Person("tdiant", "hello!!");
getConfig().set("demo", person);
saveConfig();

// 读回来
Person loaded = (Person) getConfig().get("demo");

配置文件里长这样:

yaml
demo:
  ==: com.example.Person
  name: tdiant
  introduction: hello!!

==: 那行就是类名标记。

遍历 ConfigurationSection ​

配置可能有不确定的子键(如每个玩家一个键),需要遍历。用 getKeys / getValues:

java
ConfigurationSection section = getConfig().getConfigurationSection("Data");
if (section != null) {
    // 遍历所有子键名
    for (String key : section.getKeys(false)) {
        getLogger().info("玩家: " + key);
    }

    // 遍历所有子键值
    for (String key : section.getKeys(false)) {
        int score = section.getInt(key + ".Score");
        getLogger().info(key + " 的分数: " + score);
    }
}

getKeys 的参数 ​

java
section.getKeys(false) // 只取直接子键
section.getKeys(true)  // 递归取所有后代键

区分直接子键和递归

getKeys(false) 只给第一层键名(如 player1、player2)。getKeys(true) 会把 player1.Score、player1.NickName 全部展开。遍历玩家列表用 false。

实战:遍历玩家数据 ​

配置:

yaml
Data:
  player1:
    Score: 50
    NickName: A
  player2:
    Score: 80
    NickName: B

遍历取出每个玩家分数:

java
ConfigurationSection data = getConfig().getConfigurationSection("Data");
int total = 0;
for (String name : data.getKeys(false)) {
    total += data.getInt(name + ".Score");
}
getLogger().info("总分数: " + total);

序列化解决"存对象",遍历解决"存动态数据"。下一篇多线程与多任务。