一次泛型引起的意外:java.math.BigDecimal cannot be cast to java.lang.Integer

本文详细解析了一个关于MyBatis在处理泛型时出现的类型转换异常问题,包括错误日志分析、代码审查及解决方案。通过调整XML配置文件中的类型映射,成功将返回值类型从BigDecimal更改为Integer。
咱们按照发现问题、分析问题、解决问题的思路看一下这个问题吧。


首先看看这个云里雾里的错误日志:

Caused by: java.lang.ClassCastException: java.math.BigDecimal cannot be cast to java.lang.Integer

然后根据错误日志里提示的行数找到出问题的代码行,这个方法很简单,是由Mybatis根据主键查询并返回Java对象。


检查一下Mybatis的配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.TestDao" >
  <resultMap id="BaseResultMap" type="com.test.Test" >
    <id column="ID" property="id" /> 

注意数据库字段ID和id的对应关系没有配置类型,这里Mybatis会自动返回一个java.math.BigDecimal对象。


再看看com.test.Test这个类的ID是不是BigDecimal类型的吧

public class Test extends SuperTest<Integer> implements Serializable {
    此类里没有id的定义,是在父类里定义的
}

接着看父类:

public abstract class SuperTest<ID> {
	
	private ID id;

	public ID getId() {
		return this.id;
	}

	public void setId(ID id) {
		this.id = id;
	}
        省略其他代码...
}


这里为何子类明明设定了泛型是Integer,但是最后却成了BigDecimal了呢?
原因是这样子的:
首先我们要知道在编译后会将泛型转换为Object对象的,这是为了向JDK1.5之前的版本兼容。
但是会在Test类中增加一些父类的桥方法,类就成这样了:

public class Test extends SuperTest<Integer> implements Serializable {
        public Integer getId() {
		return (Integer)this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
}



父类编译后成了这样子:

public abstract class SuperTest<ID> {
	private Object id;

	public Object getId() {
		return this.id;
	}

	public void setId(Object id) {
		this.id = id;
	}
        省略其他代码...
}

当Mybatis获取的对象返回的id是BigDecimal时,就通过Test来设置,但是没有找到setId(  BigDecimal id)的定义,于是就找到其父类setId( Object id),于是返回的对象就变成了:


Test(){
        id:类型是BigDecimal,而不是Integer
}

这个问题如何解决呢?
很简单,限制Mybatis返回的id是Integer就可以了,看下面的代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.TestDao" >
  <resultMap id="BaseResultMap" type="com.test.Test" >
    <id column="ID" property="id" javaType="int" jdbcType="INTEGER"/> 

问题迎刃而解。
这个问题是因为泛型的类型擦除有关,在有泛型的地方,一定要对此加以注意。





### 问题分析 `ClassCastException` 是 Java 中常见的运行时异常,通常发生在尝试将一个对象强制转换为不兼容的类时。具体到 `BigDecimal` 无法转换为 `Object[]` 的问题,通常是由于以下几种原因: 1. **类不兼容**:尝试将 `BigDecimal` 类的对象强制转换为 `Object[]`(对象数组),而 `BigDecimal` 本身并不是数组类。 2. **集合或数组误用**:在某些情况下,可能错误地将 `BigDecimal` 存入了 `Object[]` 类的数组中,或者试图从集合中取出 `BigDecimal` 时误用了数组类。 3. **擦除问题**:如果使用了集合,而没有在编译时严格检查类,可能会在运行时出现类转换错误。 --- ### 解决方案 #### 1. 检查变量类 确保在进行类转换之前,变量的类是兼容的。例如,如果 `obj` 是一个 `BigDecimal`,则不能直接将其转换为 `Object[]`。 ```java Object obj = new BigDecimal("123.45"); if (obj instanceof BigDecimal) { BigDecimal value = (BigDecimal) obj; System.out.println(value); } ``` #### 2. 使用数组时的正确处理 如果需要将 `BigDecimal` 放入数组中,应使用 `Object[]` 并在取出时进行类检查: ```java Object[] array = new Object[]{new BigDecimal("100.00")}; Object obj = array[0]; if (obj instanceof BigDecimal) { BigDecimal value = (BigDecimal) obj; System.out.println("Value: " + value); } ``` #### 3. 避免错误的强制类转换 不要尝试将 `BigDecimal` 强制转换为 `Object[]`,因为 `BigDecimal` 是一个数值类,而不是数组: ```java Object obj = new BigDecimal("50.00"); // 错误示例:这将抛出 ClassCastException // Object[] array = (Object[]) obj; // ❌ 不允许转换 ``` #### 4. 使用集合避免类转换问题 使用集合可以避免运行时类转换错误。例如,使用 `List<BigDecimal>` 来存储 `BigDecimal` 对象: ```java List<BigDecimal> list = new ArrayList<>(); list.add(new BigDecimal("200.00")); // 安全获取元素 BigDecimal value = list.get(0); System.out.println("Value: " + value); ``` --- ### 示例代码 以下是一个完整的示例,展示如何安全地处理 `BigDecimal` 并避免 `ClassCastException`: ```java import java.math.BigDecimal; public class BigDecimalExample { public static void main(String[] args) { Object obj = new BigDecimal("123.45"); // 安全地进行类检查和转换 if (obj instanceof BigDecimal) { BigDecimal value = (BigDecimal) obj; System.out.println("Value: " + value); } else { System.out.println("对象不是 BigDecimal"); } // 使用 Object[] 存储 BigDecimal Object[] array = new Object[]{new BigDecimal("678.90")}; Object objFromArray = array[0]; if (objFromArray instanceof BigDecimal) { BigDecimal value = (BigDecimal) objFromArray; System.out.println("数组中的值: " + value); } } } ``` --- ### 总结 在 Java 中处理 `BigDecimal` 时,应始终确保类安全,避免直接进行不兼容的类转换。使用 `instanceof` 进行类检查、使用集合、以及正确使用数组,可以有效防止 `ClassCastException` 的发生。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值