1

I already have a solution, but I don't like it. Also, it would be nice to know your thoughts about this.

You see, elem.get gives back an Object, that is going to be a Float in the case of x and y.

This code throws the Exception described in the title:

String names[] = { "x", "y", "src" };
Class types[] = { float.class, float.class, String.class };

for (int i = 0; i < names.length; i++)
{
    if (elem.containsKey(names[i]))
    {
        par.add(types[i]);
        arg.add(types[i].cast(elem.get(names[i])));
    }
}

The code is used to define the list of parameters to instantiate an object. Both the parameters and the object's class name are defined in an external data file (but nevermind about that).

The solution, something I'm not fond of (because it loses the flexibility I was trying to attain), has this within the for:

if(types[i] == float.class)
{
    float v = (Float)elem.get(names[i]);
    arg.add(v);
} else
{
    arg.add(types[i].cast(elem.get(names[i])));
    break;
}

Other option would be changing float.class to Float.class in types, but I won't do that because that code is used to instantiate objects which have float parameters in their constructors.

Thanks!

2
  • If you're using java 1.5 or higher, Floats will be auto-unboxed to floats, no? Did you try using Float.class? Commented Sep 22, 2011 at 21:28
  • As I wrote, I don't want to use Float.class, because I need the argument to be used as a float in the instantiation that I do afterwards. But if I use Float.class in this code, it works. It just fails later when trying to instantiate the Object which constructor has floats. Thanks for your answer! Commented Sep 22, 2011 at 21:31

1 Answer 1

2

As the type of args is an ArrayList<Object>, you're not avoiding the boxing anyway:

// This code...
float v = (Float)elem.get(names[i]);
arg.add(v);

// Will actually be equivalent to:
float v = (Float)elem.get(names[i]);
Float boxed = v;
arg.add(boxed);

If the point is to call a constructor by reflection, then you're going to have to pass in a Float for any float parameters - that's just how it works.

So basically, change float.class to Float.class and it should all work fine. EDIT: Ah, except then the par list will have the wrong type. Basically you want to cast with Float.class, but add float.class to the list of parameter types.

You probably want a map from primitive types to wrapper types, like this:

private static final Map<Class<?>>, Class<?>> PRIMITIVE_TYPE_MAP =
    buildPrimitiveTypeMap();

private static Map<Class<?>>, Class<?>> buildPrimitiveTypeMap()
{
    Map<Class<?>>, Class<?>> map = new HashMap<Class<?>>, Class<?>>();
    map.put(float.class, Float.class);
    map.put(double.class, Double.class);
    // etc
    return map;
}

Then:

String names[] = { "x", "y", "src" };
Class types[] = { float.class, float.class, String.class };

for (int i = 0; i < names.length; i++)
{
    if (elem.containsKey(names[i]))
    {
        par.add(types[i]);

        // For primitive types, only box to the wrapper type
        Class<?> castType = PRIMITIVE_TYPE_MAP.get(types[i]);
        if (castType == null)
        {
            castType = types[i];
        }
        arg.add(castType.cast(elem.get(names[i])));
    }
}

In fact, if you trust that the values are of the right type already, I suspect you can just do:

arg.add(elem.get(names[i]));

After all, you're just casting to a particular type and then losing that type information again... using the cast call does perform a check that the execution-time types are correct though, so you may want to keep it for that reason.

Sign up to request clarification or add additional context in comments.

10 Comments

Oops. Sorry. arg is a ArrayList<Object>.
@huff: Right, so as I thought - when you add a float to it, it'll be boxed to Float anyway. Will edit my answer to make that clearer.
Thanks! So, but when I use Float.class it doesn't find the proper constructor for the object to instantiate.
@huff: Have edited. It's slightly awkward - it would be nice if Class had a getWrapperClass method which return null for non-primitive types :( If you can trust the original data, you don't need to do the cast at all of course, which avoids the problem :)
@huff: You should go the other way: given float.class (the "correct" parameter type) you want to keep that information for the parameter types, but go to the wrapper type for the cast call. Otherwise you'll have a problem with any constructors which genuinely have a Float parameter.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.