简体   繁体   中英

Java cannot cast from boxed type to primitive type

I am trying to use Class.cast () to convert a boxed Double to the primitive double:

Object d = 1.0d;
Class<?> clazz = double.class;
//the bellow line throws java.lang.ClassCastException: 
//Cannot cast java.lang.Double to double
clazz.cast(d);

I am doing this because in some part of my code, a value object and a Class are given dynamically, and I do have the guarantee that the value object is of the compatible type. But this exception really confuses me. What is the contract of using cast () ?

UPDATE I ran into this because we have code like:

interface Provider <T> {
  T get ();
  Class<T> getClazz();
}

//a special handling for double primitive
class DoubleProvider implements Provider<Double> {

  public double getDouble(){
      return 1.0d;
  }

  @Override
  public Double get() {
    return getDouble();
  }

  @Override
  public Class<Double> getClazz() {
    //why this actually compiles?
    return double.class;
  }
}

If double and Double are so different that they are not considered assignable in neither ways, why java allow the getClazz () method in the DoubleProvider to compile? What is the relation between double.class and Double.class?

You can't cast a Double to a double (or vice versa) since neither is a subtype of the other. Use (double) which auto-unboxes the value instead.

What is the contract of using cast() ?

The javadoc for the API is the contract of the method. In this case javadoc says :

Casts an object to the class or interface represented by this Class object.

[...]

Throws: ClassCastException - if the object is not null and is not assignable to the type T.

If you need to get the primitive (unboxed) version of an Object based on the Class, I see no better way than

if (clazz == double.class)
    handleDouble((double) o);
if (clazz == int.class)
    handleInt((int) o);
...

Regarding your edit: This is because double.class has the type Class<Double> . The JLS states :

The type of p.class , where p is the name of a primitive type (§4.2), is Class<B> , where B is the type of an expression of type p after boxing conversion (§5.1.7).

Auto[un]boxing is essentially a compiler trick. Its express purpose is to conceal the fact that primitives are not assignable or castable to their corresponding wrapper class type, and vise versa . Whenever you think you are assigning a double to a variable of type Double (say), you are in fact first autoboxing the double in a Double and then assigning that, as if you had written something like this:

Double wrapper = Double.valueOf(1.0d);

Back in the day, we had to do that manually.

I am doing this because in some part of my code, a value object and a Class are given dynamically

If you are indeed receiving a value object then the problem should not arise. Primitives are not objects, and Java provides no way to handle a bona fide primitive that should allow you to confuse it with an object. If you have a method that accepts an Object reference, or if you have a variable that holds one, then you can be 100% confident that the referenced object is not a double or any other primitive, though it could be a Double or an instance of one of the other wrapper classes.

Update: If your system needs to handle values of primitive types and also of wrapper types, maintaining a distinction between them, then you probably need to provide a special case for primitives. You can identify the classes representing primitives via Class.isPrimitive() . There are exactly nine of them, including Void.TYPE .

Update2: In answer to the added question, the type of Double.TYPE (the original, still valid, spelling of double.class ) is Class<Double> . It is therefore a valid return value for a method having that return type. "Why?" questions are always a bit ticklish, but I think it's fair to deduce that at least one reason why Double.TYPE has that specific class parameter is that there isn't any better alternative. Type arguments must be names of reference types. double is not a reference type, so the type of double.class cannot be Class<double> . Class<Double> is the next-best alternative.

Note well: although Double.class and double.class both have type java.lang.Class<java.lang.Double> , they are different classes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM