【问题标题】:Java cannot cast from boxed type to primitive typeJava 不能从盒装类型转换为原始类型
【发布时间】:2015-05-13 15:12:05
【问题描述】:

我正在尝试使用 Class.cast () 将盒装 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);

我这样做是因为在我的代码的某些部分中,值对象和类是动态给出的,并且我确实保证值对象是兼容类型。但是这个例外真的让我很困惑。使用 cast() 的约定是什么?

更新我遇到了这个,因为我们有这样的代码:

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

如果 double 和 Double 如此不同以至于它们都不能被认为以任何方式赋值,为什么 java 允许 DoubleProvider 中的 getClazz() 方法进行编译? double.class 和 Double.class 是什么关系?

【问题讨论】:

  • 您不能以这种方式将包装类转换为原语。自动装箱和铸造是not the same thing

标签: java


【解决方案1】:

您不能 Double 转换为 double(反之亦然),因为两者都不是另一个的子类型。改用 (double) 自动拆箱值。

使用cast()的合约是什么?

API 的 javadoc 是方法的契约。在这种情况下javadoc says

将一个对象投射到此 Class 对象所代表的类或接口。

[...]

投掷: ClassCastException - 如果对象不为 null 且不可分配给类型 T。

如果您需要基于类获取对象的原始(未装箱)版本,我认为没有比这更好的方法了

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

关于您的编辑:这是因为 double.class 的类型为 Class&lt;Double&gt;JLS states

p.class 的类型,其中p 是原始类型的名称(§4.2),是Class&lt;B&gt;,其中B 是装箱转换后的 p 类型表达式的类型(§5.1 .7)。

【讨论】:

  • JLS 语句有道理,但是 Double.class.equals(double.class) 返回 false?
  • 是的。你说的对。我在制定答案时太快了。改写。谢谢。
【解决方案2】:

自动[取消]装箱本质上是一种编译器技巧。其明确目的是隐藏原语不可分配或转换为它们相应的包装类类型的事实,反之亦然。每当您认为将double 分配给Double 类型的变量时(例如),实际上您首先将double 自动装箱到Double 中,然后分配它,就好像您写过这样的东西:

Double wrapper = Double.valueOf(1.0d);

过去,我们必须手动完成。

我这样做是因为在我的代码的某些部分,一个值对象和一个类是动态给出的

如果您确实收到了一个值 object,那么问题应该不会出现。原语不是对象,Java 没有提供处理真正原语的方法,这会使您将其与对象混淆。如果您有一个接受 Object 引用的方法,或者如果您有一个包含一个引用的变量,那么您可以 100% 确信引用的对象不是 double 或任何其他原语,尽管它可能是Double 或其他包装类之一的实例。

更新: 如果您的系统需要处理原始类型和包装类型的值,保持它们之间的区别,那么您可能需要为原始类型提供一种特殊情况。您可以通过Class.isPrimitive() 识别表示基元的类。正好有九个,包括Void.TYPE

更新 2: 在回答添加的问题时,Double.TYPE 的类型(double.class 的原始拼写仍然有效)是Class&lt;Double&gt;。因此,对于具有该返回类型的方法来说,它是一个有效的返回值。 “为什么?”问题总是有点棘手,但我认为可以推断出Double.TYPE 具有特定类参数的至少一个原因是没有更好的选择。类型参数必须是 reference 类型的名称。 double 不是引用类型,所以double.class 的类型不能是Class&lt;double&gt;Class&lt;Double&gt; 是次佳选择。

注意:虽然Double.classdouble.class 都有type java.lang.Class&lt;java.lang.Double&gt;,但它们是不同的 类。

【讨论】:

  • 对。实际上我的情况是相反的:我得到了一个 Double 值对象和 double.class 类对象。因此,我正在尝试 double.class.cast(Double),这本质上是相同的问题。
  • @Xinchao,我已经更新了我的答案,对您的情况提出了一般性建议。
  • 谢谢!我也更新了我的问题,以包括我的另一个困惑:)
  • @Xinchao,我又更新了我的答案。但是,如果您有后续问题,那么正确的 SO 协议是将它们作为单独的问题发布。
猜你喜欢
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 2016-08-09
  • 2012-12-06
相关资源
最近更新 更多