【问题标题】:How can I make a java table where all rows can be used as keys?如何制作一个所有行都可以用作键的java表?
【发布时间】:2021-02-02 14:22:00
【问题描述】:

这对我来说很难解释,因为我不是英语母语,所以我会尝试设置一个示例。

我正在尝试将有关玩家的一些数据保存在名为 PlayerData 的类中。它具有三个带有 getter 和 setter 的变量。

public class PlayerData {

private String player;
private String username;
private UUID uuid;

public String getPlayer() {
    return player;
}

public void setPlayer(String player) {
    this.player = player;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public UUID getUuid() {
    return uuid;
}

public void setUuid(UUID uuid) {
    this.uuid = uuid;
}

}

对于游戏中的每个玩家,都会生成一个 PlayerData 对象。通常我会将其存储在地图中,因此我可以从例如获取有关玩家的数据。 UUID。但是,我可以使用一种方法来将 PlayerData 对象中的任何变量用作“键”,因此我不需要 UUID 来获取 PlayerData。一种方法(和我常用的方法)是拥有多个地图,就像这样。

Map<String, PlayerData> playerMap;
Map<String, PlayerData> usernameMap;
Map<UUID, PlayerData> uuidMap;

问题是,当它使用多个变量进行扩展时,这会变得很烦人,甚至可能会占用 RAM?我不完全确定,因为它存储引用。

它类似于 SQL,您也可以根据行的内容获取特定的列。这就是我正在寻找的,但没有 SQL 数据库。

我在下面做了一个表格解释,试图进一步解释:

Player Username UUID
Peter Peter1234 657f6c48-655f-11eb-ae93-0242ac130002
Stephen DogLover69 657f6efa-655f-11eb-ae93-0242ac130002
Joshua XxFlowerPotxX 657f6fea-655f-11eb-ae93-0242ac130002

短版 我正在寻找一种方法来存储相同类型的多个对象,其中我(与 Maps 不同,只将单个对象作为键)可以使用多个分配的变量作为键。

我希望解释清楚,我完全不知道如何解释,这可能也是我无法通过谷歌搜索解决的原因。

感谢您的宝贵时间。

【问题讨论】:

  • 除非您有一百万个或更多 PlayerData 实例,否则只需将它们放在 java.util.List 中并线性搜索 List 以查找您要查找的属性。

标签: java hashmap


【解决方案1】:

据我了解,它需要为特定用户存储各种数据(而不仅仅是更新旧值)

一种方法是通过自定义地图。由于只需要一个密钥(唯一),因此可以假设用户名正在这样做(例如:登录)。 MyData 可以根据想要存储的内容进一步定制。 每个键/用户名都将包含一个不同的列表,其中添加了新数据。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class TestPData {

    public static void main(String[] args) 
    {
        TestPData t = new TestPData();
        MyMap m = t.new MyMap();
        //key can be just user name, if unique is assured
        m.putMyData("player_1", t.new MyData("p1_data1"));
        m.putMyData("player_1", t.new MyData("p1_data2"));
        m.putMyData("player_2", t.new MyData("p2_data3"));
        m.putMyData("player_3", t.new MyData("p2_data4"));
        m.putMyData("player_3", t.new MyData("p2_data5"));
        m.putMyData("player_3", t.new MyData("p2_data6"));
        m.forEach((k,v)->{for(MyData d: v) {System.out.println(k+":"+d);}});
    }
    class MyData
    {
        String s;
        public MyData(String s)
        {
            this.s = s;
        }
        public String toString()
        {
            return s;
        }
    }
    class MyMap extends HashMap<String, List<MyData>>
    {
        private static final long serialVersionUID = 1L;

        public void putMyData(String k, MyData d)
        {
            if(!this.containsKey(k))
            {
                this.put(k, new ArrayList<MyData>());
                this.get(k).add(d);
            }
            else
            {
                this.get(k).add(d);
            }
        }
    }
}

输出

player_1:p1_data1
player_1:p1_data2
player_3:p2_data4
player_3:p2_data5
player_3:p2_data6
player_2:p2_data3

【讨论】:

    【解决方案2】:

    如果您处理的记录很少(几千条),您可以使用@gilbert-le-blanc 建议的列表和迭代搜索,但如果您需要管理大量记录/属性,最好使用无论如何都要使用数据库。您还可以使用 Derby 或 H2 等内存数据库。

    通过一些努力,您也可以创建具有多索引属性的自定义集合,但这不值得。

    【讨论】:

      【解决方案3】:

      我会使用地图的映射,第一个映射按属性名称,第二个映射按其值。

      在代码中:

      Map<String, Map<String, PlayerData>> index = new HashMap<>();
      

      添加映射:

      PlayerData peterData = new PlayerData(
          "Peter", 
          "Peter1234", 
          "657f6c48-655f-11eb-ae93-0242ac130002");
      
      index.computeIfAbsent("player", k -> new HashMap<>())
          .put("Peter", peterData);
      index.computeIfAbsent("username", k -> new HashMap<>())
          .put("Peter1234", peterData);
      index.computeIfAbsent("uuid", k -> new HashMap<>())
          .put("657f6c48-655f-11eb-ae93-0242ac130002", peterData);
      

      导航通过Map.computeIfAbsent 方法到不同的内部地图(每个索引属性一个),该方法创建一个空的内部地图,如果没有,则将其放入外部地图存在,或者如果已经存在则返回它。然后,我们照常使用Map.put 将映射添加到内部映射。

      要删除映射:

      index.computeIfAbsent("username", k -> new HashMap<>()).remove("Peter1234");
      

      这是完全动态的,因为当您需要按更多属性进行映射时,您不必更改数据结构。相反,您所要做的就是根据需要添加映射。

      这种方法的缺点是您需要使用字符串作为内部映射的键,但我认为这是一个合理的权衡。

      【讨论】:

        猜你喜欢
        • 2019-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-24
        相关资源
        最近更新 更多