问题描述:

I have the following two classes

Animal Class

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;

}

}

Dog Class

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);

}

}

As you can see from the above code I am trying to set some values with keys in index method, but I am getting error warnings from eclipse in both two files. Error Messages are:

In Dog Class File:

Multiple markers at this line

- A cannot be resolved

to a type

- A cannot be resolved

to a type

In Animal Class File :

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>>

The data type of the keys in HashMap will always be a String but the data types of values would be random, hence I am trying to use Generics.

Coming from PHP background I still haven't been able to grasp the concept of Java Generics. Could you please tell me where is the mistake in my code?

网友答案:

While this kind of setup is not the ideal way to go, one solution is to make your Map a <String, Object> generic type. In this way you can put whatever you want into the Object part. This will, however, be a pain to pull that information back out. This is how I see your classes changing.

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);
      }
    }
网友答案:

You should not be using a Map for this; this is not like PHP.

Instead you should be creating a class that knows the type of each of its fields:

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

You should really only be using a Map when all the keys and all the values have the same type.

网友答案:
A cannot be resolved to a type

It just means that you are using class "A" which does not exist. For example here Map<String, A> data you are saying, that you are creating Map, where string is key and the value is type "A".

In comparision, this Map<String, Integer> would mean, that you create map, which has string as key and integer as associated value to its key.

网友答案:

Your Map<String, A> has the undefined type A in its declaration. The problem is, that A is never specified and therefore can not be used as a Type for anyting.

The solution would be to either use the wildcard type or use Object instead of A.

Here are the two example solutions: Map<String, ?> data = new HashMap <String, ?>(); or Map<String, Object> data = new HashMap <String, Object>();

The same thing has to be applied to the map in your Dog class.

网友答案:

The problem is that you can't just introduce a type parameter in Java generics and expect it to work. For example looking at the Animal class:

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;
   }
}

Type parameter A is not defined, so in this case, the compiler will look for a class name A. You can solve that by introducing a type parameter for the class:

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;
   }
}

However the problem with this is, that you then need to define A when you initialise a new Animal for example:

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

What this means however, is that your data Map can only map from String to String, you will not be able to store integers.

You could get around this by using wildcards, like this for example:

class Animal {

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

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

Now you can store every data type derived from Object in your map, a String or even an Integer.

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

The problem with this solution is that you are only to retrieve the elements in this map in a type save manner.

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

-- but --

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

As by this stage, the type information has been lost and you are left with a map that maps String to Object

相关阅读:
Top