有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Perl哈希的Java等价物

由于超级灵活和方便,我一直在使用很多Perl哈希。 例如,在Perl中,我可以执行以下操作:

$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}

我想知道如何用Java完成同样的事情,我想这与HashMap有关

谢谢


共 (6) 个答案

  1. # 1 楼答案

    请参阅Map接口及其实现,特别是HashMap

    请注意,Java没有Perl的自动生动化(方便但dangerous特性),因此

    hash.get("areaCode").get("phone").get("streetAdr")
    

    如果get(phone)返回null,将抛出异常。 还要注意,您不应该对具有固定名称(“属性”)的对象使用哈希,您应该使用其getter和setter定义自己的类

  2. # 2 楼答案

    首先,您的特定示例($hash{AREA_CODE}->{PHONE}->{STREET_ADDR})使用硬编码字符串作为散列键,正如Michael Carman指出的那样,它在Java中并不是一个真正有用的数据结构——它应该存储为一个带有属性的类(老实说,它在概念上是一个糟糕的数据结构——像这样的数据更可能是一个电话数组,而不是电话散列)

    第二,假设你的意思是$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR},到目前为止,似乎每个人的Java代码都没有实现通用的等效代码——这些代码都假设Java哈希是新初始化的,用于存储示例,或者是完全填充的,用于检索示例(换句话说,正如leonbloy的回答所指出的,缺少自动激活功能)

    模拟自生的正确代码是:

    // This method will ensure that hash-of-hash-of-hashes structure exists of a given set of 3 keys.
    public HashMap<String, HashMap<String, HashMap<String, Object>>>
     autovivification_3rd_level (
               HashMap<String, HashMap<String, HashMap<String, Object>>> hash
             , String AREA_CODE, String PHONE, String STREET_ADDR) {
        if (hash == null) {
            hash = new HashMap<String, HashMap<String, HashMap<String, Object>>>();
        }
        if (!hash.contains(AREA_CODE) || hash.get(AREA_CODE) == null) {
            hash.put(new HashMap<String, HashMap<String, Object>>());
        }
        HashMap<String, HashMap<String, Object>> AREA_CODE_hash
             = (HashMap<String, HashMap<String, Object>>) hash.get(AREA_CODE);
        if (!AREA_CODE_hash.contains(PHONE) || AREA_CODE_hash.get(PHONE) == null) {
            AREA_CODE_hash.put(new HashMap<String, Object>());
        }
        return hash;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////    
    
    // Equivalent to Perl's "$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR} = value;"
    public Object put_3d_level_hash(
              HashMap<String, HashMap<String, HashMap<String, Object>>> hash
            , String AREA_CODE, String PHONE, String STREET_ADDR,
            , Object value) {
        hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
        return hash.get(AREA_CODE).get(PHONE).put(STREET_ADDR, value);
    }
    put_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR, obj);
    
    ////////////////////////////////////////////////////////////////////////////////////    
    
    // Equivalent to Perl's "$var = $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}"
    public Object get_3d_level_hash(HashMap<String, HashMap<String, HashMap<String, Object>>> hash
                           , String AREA_CODE, String PHONE, String STREET_ADDR) {
        hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
        return hash.get(AREA_CODE).get(PHONE).get(STREET_ADDR);
    }
    Object obj = get_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR);
    
  3. # 3 楼答案

    你可以很容易地将你的散列子类化,以添加一个可以为你自动激活的方法

    发件人:$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}

    致:hash.vivifyingGet(areaCode).put(phone, streetAddr)

    假设我已使用以下内容创建哈希:

    /**
      * A two-level autovivifying hashmap of X and Y to Z. Provides
      * a new method #vivifyingGet(X) which creates the next level of hash.
      */
    Map<AreaCode, Map<Phone, StreetAddr>> hash =
        new HashMap<AreaCode, Map<Phone, StreetAddr>>() {
        /**
          * Convenience method to get or create the next level of hash.
          * @param key the first level key
          * @return the next level map
          */
        public Map<Phone, StreetAddr> vivifyingGet(Phone key) {
            if (containsKey(key)) {
                return get(key);
            } else {
                Map<Phone, StreetAddr> = hash = new HashMap<Phone, StreetAddr>();
                put(key, hash);
                return hash;
            }
        }
    };
    
  4. # 4 楼答案

    如果散列键是常量,为什么hash.getAreaCode().getPhone().getStreetAddr()不这样做?请记住,getter或构造函数都需要处理默认值生成

  5. # 5 楼答案

    Java有散列,但由于强类型,它们不如Perl中的散列灵活。多维哈希更难使用。在Perl中,您只需声明一个散列,并让autovivification根据需要创建嵌套的散列

    my %hash;
    $hash{a}{b} = 1;
    

    在Java中,必须先声明它是散列

    Map<String,Map<String,Integer>> hash = new HashMap<String,HashMap<String,Integer>>();
    hash.put("a", new HashMap<String, Integer>());
    hash.get("a").put("b", new Integer(1));
    

    对于每个额外的维度,您需要向声明中添加另一个Map<K,V>嵌套。除了单调乏味之外,这并不是很糟糕

  6. # 6 楼答案

    I've been using a lot Perl hashes due to super flexibility and convenient. for instance, in Perl I can do the following: $hash{AREA_CODE}->{PHONE}->{STREET_ADDR} I wondering how can I accomplish the same thing with Java, I guess it has something to do with HashMap?

    Java代码近似于以下Perl代码:

    my %hash;
    $hash{AREA_CODE}{PHONE}{STREET_ADDR} = "221B Baker Street";
    printf "Street address is %s\n", $hash{AREA_CODE}{PHONE}{STREET_ADDR};
    

    HashMap<String, HashMap<String, HashMap<String, String>>> hash =
        new HashMap<String, HashMap<String, HashMap<String, String>>>();
    
    hash.put("AREA_CODE", new HashMap<String, HashMap<String, String>>());
    hash.get("AREA_CODE").put("PHONE", new HashMap<String, String>());
    hash.get("AREA_CODE").get("PHONE").put("STREET_ADDR", "221B Baker Street");
    
    System.out.printf("Street address is %s\n",
        hash.get("AREA_CODE").get("PHONE").get("STREET_ADDR"));
    

    这不是很特别吗

    我说“近似”有很多原因。其中一个原因是,在Java中,仅仅因为想要在Java的下一行中执行与此完全直接的Perl代码等效的操作,您就会被挫败到极点:

    $hash{AREA_CODE}{PREFIX} = 800;
    

    如果您想要Perl在这类事情上的灵活性和便利性,Java根本不会给您。更糟糕的是,它的支持者经常会因为你表达了这样的愿望而斥责你