反射==>获得泛型的实际类型参数

本文介绍了一种使用Java反射机制来获取方法签名中泛型参数实际类型的方法。通过实例演示了如何从带有泛型参数的方法中提取具体类型信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.interview.getGenericArgument;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
 * 通过反射技术得到泛型的实际类型参数
 * @author dhh
 *
 */
public class GetGernericArgument {
	public static void main(String[] args) {
		List<Date> lists = new ArrayList<Date>();
		List<String> lists2 = new ArrayList<String>();
		/**
		 * 如果想通过lists,lists2来得到lists的实际类型参数(也就是Date)
		 * 这是不能实现的,因为泛型就是编译器用来防止开发者不按实际类型胡乱
		 * 添加。它编译完之后成class之后,将没有泛型这个概念,
		 * 因为lists.getClass()==list2.getClass()
		 * 但是如果要得到方法里面的实际类型参数,就可以实现
		*/
		//得到getActualArgument方法的实际类型参数
		try {
			Method method =
				GetGernericArgument.class.getMethod("getActualArgument", ArrayList.class,HashMap.class);
			//得到所有泛型参数类型,不能用method.getParameterTypes(),因为class中不包含泛型类型
			Type[] types = method.getGenericParameterTypes();
			System.out.println("**---------第一个参数-------**");
			//Type包含很多种,我们要得到参数化的Type.ParameterizedType 表示参数化类型,如 Collection<String>
			ParameterizedType paramType = (ParameterizedType)types[0];
			//返回 Type 对象,表示声明此类型的类或接口(原始类型)
			System.out.println(paramType.getRawType());
			//得到第一个参数的类型,如果是HashMap<K,V>将会有两个参数
			//返回表示此类型实际类型参数的 Type 对象的数组。
			System.out.println(paramType.getActualTypeArguments()[0]);  
			
			System.out.println("**---------第二个参数-------**");
			//Type包含很多种,我们要得到参数化的Type.ParameterizedType 表示参数化类型,如 Collection<String>
			ParameterizedType paramType2 = (ParameterizedType)types[1];
			System.out.println(paramType2.getRawType());
			System.out.println(paramType2.getActualTypeArguments()[0]);
			System.out.println(paramType2.getActualTypeArguments()[1]);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 通过方法得到参数的实际类型参数
	 * @param lists
	 * @param maps
	 */
	public void getActualArgument(ArrayList<Date> lists,HashMap<Integer, String> maps){}
}

public int insertDeptList(List<Map<String,String>> deptList);这是接口, <insert id="insertDeptList" parameterType="java.util.List"> INSERT INTO sys_dept ( <if test="deptList[0].parent_id != null">parent_id,</if> <if test="deptList[0].ancestors != null">ancestors,</if> <if test="deptList[0].dept_name != null">dept_name,</if> <if test="deptList[0].order_num != null">order_num,</if> <if test="deptList[0].leader != null">leader,</if> <if test="deptList[0].phone != null">phone,</if> <if test="deptList[0].email != null">email,</if> <if test="deptList[0].status != null">status,</if> <if test="deptList[0].del_flag != null">del_flag,</if> <if test="deptList[0].create_by != null">create_by,</if> create_time, <if test="deptList[0].update_by != null">update_by,</if> <if test="deptList[0].update_time != null">update_time,</if> <if test="deptList[0].org_index_code != null">org_index_code,</if> <if test="deptList[0].org_no != null">org_no,</if> <if test="deptList[0].org_path != null">org_path,</if> <if test="deptList[0].parent_org_index_code != null">parent_org_index_code,</if> <if test="deptList[0].parent_org_name != null">parent_org_name,</if> ) VALUES <foreach collection="deptList" item="item" separator=","> ( <if test="item.parent_id != null">#{item.parentId},</if> <if test="item.ancestors != null">#{item.ancestors},</if> <if test="item.dept_name != null">#{item.deptName},</if> <if test="item.order_num != null">#{item.orderNum},</if> <if test="item.leader != null">#{item.leader},</if> <if test="item.phone != null">#{item.phone},</if> <if test="item.email != null">#{item.email},</if> <if test="item.status != null">#{item.status},</if> <if test="item.del_flag != null">#{item.delFlag},</if> <if test="item.create_by != null">#{item.createBy},</if> sysdate(), <if test="item.update_by != null">#{item.updateBy},</if> <if test="item.update_time != null">#{item.updateTime},</if> <if test="item.org_index_code != null">#{item.orgIndexCode},</if> <if test="item.org_no != null">#{item.orgNo},</if> <if test="item.org_path != null">#{item.orgPath},</if> <if test="item.parent_org_index_code != null">#{item.parentOrgIndexCode},</if> <if test="item.parent_org_name != null">#{item.parentOrgName},</if> ) </foreach> </insert>这是代码,nested exception is org.apache.ibatis.binding.BindingException: Parameter 'deptList' not found. Available parameters are [arg0, collection, list]这是报错
最新发布
08-05
<think>我们正在解决MyBatis批量插入部门列表时出现的参数绑定异常问题。根据引用[1]和引用[2]中的信息,异常信息类似于:`Parameter 'deptList' not found. Available parameters are [collection, list]` 或类似提示。这表明MyBatis在映射参数时没有找到名为`deptList`的参数,而是提供了可用的参数名如`collection`或`list`。 原因分析: 在MyBatis中,当我们传入一个集合(List)作为参数时,MyBatis默认会将其转换为一个Map,其中包含两个键: - `list`:指向传入的List对象 - `collection`:同样指向传入的List对象(在MyBatis 3.3.0及之前,只有`list`和`collection`这两个别名,而在3.3.1之后,MyBatis增加了对`arg0`和`param1`的支持,但集合类型仍然有特殊处理) 因此,在Mapper XML文件中,如果我们直接使用`#{deptList}`来引用传入的List参数,MyBatis会找不到这个参数,因为MyBatis并没有使用我们定义的参数名(例如`deptList`)来存储,而是使用了默认的`list`或`collection`。 解决方案: 1. 使用默认的参数名`list`或`collection`: 在Mapper XML文件中,将`#{deptList}`改为`#{list}`或`#{collection}`。但是这种方法可读性差,且容易混淆。 2. 使用@Param注解指定参数名(推荐): 在Mapper接口的方法参数前添加`@Param`注解,为参数指定一个名字,然后在XML中使用这个名字。 例如,将接口方法: int batchInsertDepts(List<Dept> deptList); 改为: int batchInsertDepts(@Param("deptList") List<Dept> deptList); 然后在XML中,我们就可以使用`#{deptList}`来引用这个参数了。同时,在动态SQL(如foreach)中,我们可以这样写: <foreach collection="deptList" item="dept" separator=","> (#{dept.name}, #{dept.code}) </foreach> 3. 如果使用MyBatis 3.4.1及以上版本,可以修改配置参数`useActualParamName`(默认值为true),这样MyBatis会使用实际参数名(但要求编译时开启参数保留,比如使用Java 8的-parameters选项或使用IDE的保留参数名编译选项)。但是,对于集合类型,仍然建议使用@Param注解以避免混淆。 根据引用[3]和[4]的内容,我们还可以了解到,MyBatis的binding模块是为了提前发现接口方法与XML之间的绑定错误,类似于的作用。因此,正确的参数绑定非常重要。 具体步骤: 假设我们有一个批量插入部门的方法,接口定义如下: public interface DeptMapper { int batchInsertDepts(List<Dept> deptList); } 出现异常的原因是,在XML中我们可能这样写: <insert id="batchInsertDepts"> INSERT INTO dept (name, code) VALUES <foreach collection="deptList" item="dept" separator=","> (#{dept.name}, #{dept.code}) </foreach> </insert> 这里,`collection="deptList"`会导致异常,因为MyBatis并不知道`deptList`这个参数名。 修改方法: 在接口方法上添加@Param注解: int batchInsertDepts(@Param("deptList") List<Dept> deptList); 这样,在XML中就可以使用`deptList`作为集合参数名了。 另外,如果不想修改接口,也可以将XML中的`collection`属性改为`list`(因为MyBatis默认给List类型参数取名为`list`): <foreach collection="list" item="dept" separator=","> (#{dept.name}, #{dept.code}) </foreach> 但是,这种方法在方法有多个参数时容易出错,因此推荐使用@Param注解。 总结: 出现`Parameter 'deptList' not found`异常的原因是MyBatis对集合参数使用了默认的命名(`list`或`collection`),而不是我们定义的参数名。通过使用@Param注解明确指定参数名,可以解决这个问题。 如果问题仍然存在,请检查MyBatis的版本,并确保在配置中正确设置了参数名的处理方式(如`useActualParamName`)。另外,确保在编译时保留了方法参数名(对于Java 8及以上,可以在编译时添加`-parameters`选项;对于Maven项目,可以在`maven-compiler-plugin`中配置)。 相关问题: 1. MyBatis中如何传递多个参数? 2. 除了@Param注解,还有哪些方式可以解决参数绑定问题? 3. MyBatis的foreach标签有哪些属性?分别是什么作用?</think>### 解决 MyBatis 插入部门列表时参数绑定异常 当 MyBatis 批量插入部门列表出现 `Parameter 'deptList' not found` 异常时,根本原因是 **MyBatis 对集合类型参数的默认命名规则与自定义参数名不匹配**。以下是完整解决方案: --- ### 原因分析 1. **MyBatis 的集合参数默认命名规则**([^2]): - 直接传入 `List` 时,MyBatis 会将其转换为内置参数名 `list` 或 `collection` - 错误示例:`batchInsertDepts(List<Dept> deptList)` 在 XML 中直接使用 `#{deptList}` 会报错 2. **参数绑定机制**: - MyBatis 通过反射获取参数名,若编译未保留参数名(如未加 `-parameters` 编译选项),会使用 `param1, param2...` 代替([^4]) --- ### 解决方案(推荐两种) #### ✅ 方案一:使用 `@Param` 注解显式命名(最佳实践) ```java // Mapper 接口修改 int batchInsertDepts(@Param("deptList") List<Dept> deptList); // 关键注解 ``` ```xml <!-- XML 中使用自定义名称 --> <insert id="batchInsertDepts"> INSERT INTO dept(name, code) VALUES <foreach collection="deptList" item="dept" separator=","> <!-- 此处匹配 deptList --> (#{dept.name}, #{dept.code}) </foreach> </insert> ``` #### ✅ 方案二:使用 MyBatis 内置默认名称 ```xml <foreach collection="list" item="dept" separator=","> <!-- 使用默认名称 list --> (#{dept.name}, #{dept.code}) </foreach> ``` --- ### 其他注意事项 1. **MyBatis 版本问题**: ```xml <!-- 建议使用较新版本(3.5+) --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> <!-- 最低要求 1.3.2+ 避免旧版 bug [^3] --> </dependency> ``` 2. **编译参数设置**(Maven 示例): ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <compilerArgs> <arg>-parameters</arg> <!-- 保留参数名 --> </compilerArgs> </configuration> </plugin> ``` 3. **参数检查清单**: - 确认 `collection` 属性值与 `@Param` 或默认名一致 - 确保 `item` 属性(如 `dept`)与 `#{dept.xxx}` 匹配 - 检查 SQL 语句中无其他未定义参数 --- ### 根本原理解析 MyBatis 处理集合参数时,会将其封装为 `Map` 对象: ```java // 未用 @Param 时实际参数结构 map.put("list", deptList); // 默认 key1 map.put("collection", deptList); // 默认 key2 ``` 使用 `@Param("deptList")` 后: ```java map.put("deptList", deptList); // 自定义 key 生效 ``` 这种设计确保了类型安全,类似 Java 机制([^4])。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值