2

I am having a data structure (LinkedHashMap) but the problem is that the (second) value should be of variable type since I can put there type String or type int or any primitive type so my question is:

Is there a way to define a variable type for it that can get any value type?

This is what I'm having:

private LinkedHashMap<String, String> keyVal;

I want something like this:

private LinkedHashMap<String, anyValue> keyVal;
DarkAjax
  • 15,955
  • 11
  • 53
  • 65
Jean Tennie
  • 253
  • 1
  • 5
  • 17
  • Exactly this is what generics are trying to help avoid! If you need this, there is most likely a problem in what you want ot accomplish. But if you want to go this way, ` extends Object>` is what you need... – ppeterka Mar 19 '13 at 16:29
  • I assume you want to *use* `java.util.LinkedHashMap` but don't want to specify the second type argument? – user905686 Mar 19 '13 at 16:39

7 Answers7

2
private LinkedHashMap<String, Object> keyVal;

You can use Object for that. But do remember that while trying to get data back from this map(sometime later), you may face difficulty in casting the Object to your required data type, as you may not know, what data type is actually present.

Hence, its advisable to avoid such implementations.

Rahul
  • 44,383
  • 11
  • 84
  • 103
  • Can you think about some other solution ,what i was tried to do is to pharse json object to key value list and than work on it with the respective types... – Jean Tennie Mar 19 '13 at 17:10
1

You cannot have a generic type be a primitive type. If you want to be able to store anything in your map, you can have the "value" generic type for the map be Object:

private LinkedHashMap<String, Object> keyVal;

You can still store what looks like primitives types due to autoboxing, i.e.

keyVal.put("one", 1);

will place an Integer, even though you specified an int.

rgettman
  • 176,041
  • 30
  • 275
  • 357
1

No, the closest you can have is Object as a second argument.

Now, I would advise to rethink what you need to accomplish, since this is actually going against what generics were created for.

If you have a bound type and want to maintain some flexibility, then you could use something like <String, ? extends SomeType>.

Mixing several types of Objects in the same data-structure is not advisable in Java (if this is good or bad, is beside the point), but type safety goes a long way in preventing weird errors along the line.

Try to think about how you would deal with this when you actually need to retrieve the objects... will you assume they're Strings? What are you going to do with them?

pcalcao
  • 15,789
  • 1
  • 44
  • 64
1

You say you want to have a Map< String, Primitive type>.

A specified by the JLS, primitives are NumericType or boolean, NumericType are IntegralType or FloatingPointType.

If your need is not primitive but only NumericType, you may use java.lang.Number:

Map< String, Number >

Another way is to define a class Any which hold all the possible attributes:

enum Type {
    NULL,
    INTEGER,
    SHORT,
    FLOAT,
    ...
}

class Any {
   private int   iValue;
   private short sValue;
   private float fValue;
   ...
   private Type  active = Type.NULL;

   public void setInt( int value ) {
      iValue = value;
      active = Type.INTEGER;
   }
   public void setFloat( float value ) {
      fValue = value;
      active = Type.FLOAT;
   }
   ...
   public int getInt() {
      if( type !=  Type.INTEGER ) {
         throw new ClassCastException( type.name() + " is not an integer" );
      }
      return iValue;
   }
   ...
}

It's up to you to put some check and throw exception if getInt() is called on a float holder. Everything is possible, transtyping like C language for example.

EDIT

You want String too, and String isn't a primitive.

You have to add the following below private short sValue; into the Any class:

private String sValue;

and the followinf below SHORT, into the Type enum:

STRING,

But, like others says, the best way is to avoid these weak type (fourre-tout in french).

Aubin
  • 14,617
  • 9
  • 61
  • 84
1

You can use

private LinkedHashMap<String, Object> keyVal;

to leave the second type argument as general as possible. It allows you to store any object as a value, because every class extends Object.

This leads you to the problem that you don't know what type of things are inside your map - you only know that they are of type Object what means you don't know anything.

So to use these objects again you would have to cast them back to their original type what may cause a runtime exception: ClassCastException.

Generics are about defining data structures for different types with the same code, but if you want to use a generic class you have to parameterize it with its type arguments. This ensures that the type is known at runtime and is the great advantage of generics (avoid ClassCastException). However, you can still specify a more general type that allows multiple types.

For example, if you define it the following way you can store any object that implements Serializable.

private LinkedHashMap<String, ? extends Serializable> keyVal;

As you can see, this allows you to restrict the permitted types to a common property (i.e., to be a subclass of a more general type). That way, you use the map's values as objects of the more general class, because it's everything you know (and want to know) about the objetcs.

Community
  • 1
  • 1
user905686
  • 4,491
  • 8
  • 39
  • 60
0
  1. It's better to have a look at: Generics lesson on Oracle.com.
  2. Care when should use wild cards (?) and you should use Generics.
  3. Using Object in type of LinkedHashMap<String, Object> keyVal; is not recommended.
0

Like some people said, you could use Object for generic variable type, especially while using generic method or not knowing what data type user would come, like this simple one:

import java.util.Scanner;

public class GenericMethod {
    public static void main(String[] args) {
        System.out.println("Type something that's yours: ");

        Scanner sc = new Scanner(System.in);

        Object thing;
        thing = sc.next();
        isMine(thing);
    }

    // Generic Method
    public static <T> void isMine(T x) {
        System.out.println(x + " is mine.");
    }
}