Spring不支持带泛型创建对象

问题引入:
BaseDaoImpl<T>为什么不能在applicationContext.xml文件中创建bean。
实例:

解析:
类似于本例中的构造方法,在方法中,需要得到BaseDaoImpl<T>中的泛型,则先将通过this.getClass()方法获取BaseDaoImpl<T>,然后转换为ParameterizedType类( 参见末尾附言部分 ),然后通过ParameterizedType.getActualTypeArguments();方法可以得到<>中的所有泛型类型,但是如果将BaseDaoImpl在applicationContext.xml文件中创建bean,然后以此获取BaseDaoImpl对象进行使用,如图:

则运行时会报如下错误:

ERROR:Class类型不能转换为ParameterizedType类型
疑问:
BaseDaoImpl<T>不是泛型嘛,为什么不能转换为ParameterizedType类型。
原因:
Spring不支持带泛型的类创建对象,因此,当Spring为BaseDaoImpl<T>创建对象时,只把BaseDaoImpl<T>当做BaseDaoImpl进行创建,因此this.getClass().getGenericSuperclass()返回的是class类型,而不是ParameterizedType,所以也就无法从Class类型转换为ParameterizedType类型。

附言:
ParameterizedType就是Java中的泛型,属于Type的子类。
ParameterizedType.getActualTypeArguments(), (Actual:真实的,目前的,实际的;Arguments:参数)字面翻译为: 得到真实的类型参数,即泛型对应的真实类。
<think> 我们正在讨论使用创建对象,特别是通过反射机制。用户的问题集中在“创建对象的方法”,根据引用内容,我们可以总结如下: 关键点: 1. 在方法中,由于类擦除,无法直接使用`new T()`创建对象(编译时类不确定)。 2. 解决方案是利用反射,通过传入的`Class<T>`参数来创建实例。 3. 引用[2]提供了一个示例:`T t = clazz.newInstance();`(注意:`newInstance()`方法在Java 9后被标记为过时,推荐使用`clazz.getDeclaredConstructor().newInstance()`)。 步骤: 1. 定义一个方法,参数为`Class<T>`类。 2. 在方法内部,调用`clazz.getDeclaredConstructor().newInstance()`来创建类`T`的实例。 3. 然后可以操作这个对象(如设置属性)。 注意事项: - 需要处理反射相关的异常(如`InstantiationException`, `IllegalAccessException`, `NoSuchMethodException`, `InvocationTargetException`)。 - 确保类`T`有一个无参构造器(或者使用有参构造器,需要传递对应参数)。 示例代码(更新后的写法): ```java public static <T> List<T> createObjects(Class<T> clazz) throws Exception { List<T> list = new ArrayList<>(); // 假设我们要创建两个对象 for (int i = 0; i < 2; i++) { // 使用无参构造器创建实例 T obj = clazz.getDeclaredConstructor().newInstance(); // 可以在这里设置对象的属性(通过反射) // ... list.add(obj); } return list; } ``` 如果类`T`没有无参构造器,则需要获取有参构造器并传递参数: ```java // 假设有一个有参构造器,参数为String和int Constructor<T> constructor = clazz.getDeclaredConstructor(String.class, int.class); T obj = constructor.newInstance("test", 123); ``` 引用说明: - 引用[1]提到:因为不知道具体类和构造方法,所以不能直接new,而是利用反射(通过传入的Class对象的newInstance方法)。 - 引用[2]给出了一个具体的方法,通过反射创建对象并设置属性(尽管其中使用了过时的newInstance()方法,但思路一致)。 - 引用[3]介绍了反射的基本概念,包括获取Class对象的方法。 - 引用[4]提到了C#中的类似做法(但用户主要关注Java)。 因此,回答应围绕如何通过反射在方法中创建对象,并强调需要传入Class对象作为参数。 生成相关问题: 1. 为什么在方法中不能直接使用`new T()`来创建对象? 2. 除了反射,还有其他方式在创建对象吗? 3. 如何通过反射调用有参构造器来创建对象? 4. 反射创建对象有什么优缺点? </think> ### 创建对象的方法详解 在Java中,由于类擦除机制,无法直接使用`new T()`创建对象(编译后类信息会丢失)。但可以通过反射机制实现对象的创建,核心方法如下: #### 1. **基本实现方法(使用`Class<T>`参数)** ```java public static <T> T createInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException { return clazz.newInstance(); // 调用无参构造器 } ``` - **说明**:传入具体的`Class`对象(如`String.class`),通过反射调用默认无参构造器创建实例 - **局限**:要求类必须有可访问的无参构造器[^1] #### 2. **增强实现(支持有参构造器)** ```java public static <T> T createInstance(Class<T> clazz, Object... args) throws Exception { // 获取参数类数组 Class<?>[] paramTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { paramTypes[i] = args[i].getClass(); } // 获取构造器并创建实例 Constructor<T> constructor = clazz.getDeclaredConstructor(paramTypes); return constructor.newInstance(args); } ``` - **使用示例**: ```java // 调用有参构造器:new Person("Alice", 30) Person p = createInstance(Person.class, "Alice", 30); ``` #### 3. **集合对象创建(反射生成集合)** ```java public static <T> List<T> createList(Class<T> clazz, int size) throws Exception { List<T> list = new ArrayList<>(); for (int i = 0; i < size; i++) { list.add(clazz.getDeclaredConstructor().newInstance()); } return list; } ``` ### 关键注意事项 1. **构造器要求**: - 无参构造器需为`public`(或通过`setAccessible(true)`突破访问限制) - 有参构造器需精确匹配参数类[^2] 2. **异常处理**: ```java try { MyClass obj = createInstance(MyClass.class); } catch (InstantiationException | IllegalAccessException e) { // 处理构造失败(如抽象类、接口) } catch (NoSuchMethodException e) { // 处理无匹配构造器 } ``` 3. **性能考量**: - 反射操作比直接`new`慢约3-10倍 - 高频场景建议缓存`Constructor`对象[^4] ### 应用场景 1. 框架开发(如SpringBeanFactory) 2. 序列化/反序列化工具 3. 动态代理实现 4. 单元测试Mock对象生成 > 提示:Java 8+推荐使用`clazz.getDeclaredConstructor().newInstance()`替代已废弃的`clazz.newInstance()`[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值