使用泛型的Hashmap的getter setter

时间:2014-10-10 18:52:30

标签: java generics

我有以下两个类

动物类

class Animal {

  Map<String, A> data = new HashMap <String, A>();

  public void setValue(HashMap<String, ?> val)
   {
     this.data = val;
   }
  public Map getValue()
   {
    return this.data;
   }
}

狗类

class Dog extends Animal {

  public void index()
  { 
    Map<String, A> map = new HashMap<String, A>();

    map.put("name", "Tommy");
    map.put("favfood", "milk"); // want to pass Lists, Integers also
    setValue(map);
  }
}

从上面的代码中我可以看到,我正在尝试使用index方法中的键设置一些值,但是我在两个文件中都收到来自eclipse的错误警告。错误消息是:

在狗类文件中:

Multiple markers at this line
    - A cannot be resolved 
     to a type
    - A cannot be resolved 
     to a type

在动物类文件中:

Multiple markers at this line
    - A cannot be resolved to a type
    - A cannot be resolved to a type
    - Incorrect number of arguments for type Map<K,V>; it cannot be parameterized with arguments 
     <HashMap<String,A>>

HashMap中键的数据类型将始终为String,但值的数据类型将是随机的,因此我尝试使用泛型。

来自PHP背景我仍然无法掌握Java Generics的概念。你能告诉我我的代码中的错误在哪里吗?

6 个答案:

答案 0 :(得分:1)

你应该为此使用Map;这不像PHP。

相反,您应该创建一个知道每个字段类型的类:

class Animal {
  String name;
  String favfood;
  int someIntegerField;
  List<Foo> someListField;
  ...
}

当所有键和所有值具有相同类型时,您应该只使用Map

答案 1 :(得分:1)

虽然这种设置不是理想的方法,但一种解决方案是使您的Map成为<String, Object>泛型类型。通过这种方式,您可以将任何想要的内容放入Object部分。然而,将这些信息撤回是一种痛苦。这就是我看到你的课程发生变化的方式。

class Animal {

      Map<String, Object> data = new HashMap <String, Object>();

      public void setValue(Map<String, Object> map)
       {
         this.data = map;
       }
      public Map<String, Object> getValue()
       {
        return this.data;
       }
    }

class Dog extends Animal {

      public void index()
      { 
        Map<String, Object> map = new HashMap<String, Object>();

        map.put("name", "Tommy");
        map.put("favfood", "milk"); // want to pass Lists, Integers also
        setValue(map);
      }
    }

答案 2 :(得分:0)

A cannot be resolved to a type

这只意味着你正在使用课程&#34; A&#34;哪个不存在。例如,你在Map<String, A> data说,你正在创建Map,其中string是键,值是&#34; A&#34;。

在比较中,这个Map<String, Integer>意味着你创建了map,它将string作为键,整数作为其键的关联值。

答案 3 :(得分:0)

您的Map<String, A>在其声明中包含未定义的类型A。 问题是,A从未指定,因此不能用作任何类型。

解决方案是使用通配符类型或使用Object代替A

以下是两个示例解决方案:     Map<String, ?> data = new HashMap <String, ?>(); 要么     Map<String, Object> data = new HashMap <String, Object>();

同样的事情必须应用于Dog班级的地图。

答案 4 :(得分:0)

问题是你不能在Java泛型中引入一个类型参数并期望它能够工作。例如,查看Animal类:

class Animal {

  Map<String, A> data = new HashMap <String, A>();

  public void setValue(HashMap<String, ?> val)
   {
     this.data = val;
   }
  public Map getValue()
   {
    return this.data;
   }
}

未定义类型参数A,因此在这种情况下,编译器将查找类名A。您可以通过为类引入类型参数来解决此问题:

class Animal<A> { // <--- <A> introduces A as a type parameter

  Map<String, A> data = new HashMap <String, A>();

  public void setValue(HashMap<String, ?> val)
   {
     this.data = val;
   }
  public Map getValue()
   {
    return this.data;
   }
}

但问题是,您需要在初始化新A时定义Animal,例如:

Animal<String> dog = new Animal<>();
dog.setValue("name", "max");  //<---- ok
dog.setValue("age", 13);      //<---- won't compile

但是,这意味着您的data地图只能从String映射到String,您将无法存储整数。

你可以通过使用通配符解决这个问题,例如:

class Animal {

  Map<String, ?> data = new HashMap <String, A>(); 

  public void setValue(HashMap<String, ?> val)
   {
     this.data = val;
   }
  public Map getValue()
   {
    return this.data;
   }
}

现在,您可以在地图中存储从Object派生的每种数据类型,String甚至Integer

Animal dog = new Animal();
dog.setValue("name", "max");  //<---- ok
dog.setValue("age", 13);      //<---- ok

此解决方案的问题在于您只能以类型保存方式检索此地图中的元素。

dog.getValue().get("name")  //<---- ok 
Object name = dog.getValue().get("name")  //<---- ok 

- 但是 -

String name = dog.getValue().get("name")  //<---- won't compile

在此阶段,类型信息已丢失,您将看到一张将String映射到Object的地图

答案 5 :(得分:0)

请记住,您不应混合使用 Generic type 和 RAW type same 。我认为最简单的方法是使用 Object 代替 A :

Map<String, Object> data = new HashMap <String, Object>();