通过例子体现泛型擦除特性
通过Spring拷贝方法演示
1、演示代码
定义了公用的泛型拷贝对象(源对象和目标对象),里面包含list的泛型属性;
import org.springframework.beans.BeanUtils; import java.util.ArrayList; import java.util.List; class CopyObj<T> { private List<T> list; public List<T> getList() { return list; } public void setList(List<T> list) { this.list = list; } } /** * @author Green * @date 2021年12月31日 11:11 上午 */ public class CopyTest { public static void main(String[] args) { // 定义包含List<String>属性的源对象 CopyObj<String> strCopyObj = new CopyObj<>(); List<String> stringList = new ArrayList<>(); stringList.add("abc1"); stringList.add("abc2"); stringList.add("abc3"); strCopyObj.setList(stringList); // 定义包含List<Integer>属性的目标对象 CopyObj<Integer> intCopyObj = new CopyObj<>(); List<Integer> integerList = new ArrayList<>(); intCopyObj.setList(integerList); // 通过spring拷贝对象,只要属性名和属性类型能够对应上都会进行拷贝 // 运行时泛型擦除了,所以泛型对不上并不影响 // 两个对象中都包含名为list 类型为java.util.List 的属性,所以这两个属性会进行拷贝 // 但是拷贝之后目标对象intCopyObj中存储的是源对象strCopyObj中属性list的值, // 也就是讲string类型的值拷贝到了intCopyObj对象中的List<Integer>类中属性中 // 拷贝可成功,因为泛型擦除,实际拷贝进的属性类型是List BeanUtils.copyProperties(strCopyObj, intCopyObj); // 这里是拷贝 // 但是这里遍历会出问题,因为编译时会检测泛型, // 要想编译通过,目标对象的属性编译时是Integer类型,但实际运行是这里存储的是String类型 // 所以这里遍历会报错类型转换异常 for (Integer integer : intCopyObj.getList()) { System.out.println("success!"); } } }
2、debug详情
拷贝是可以完成的,目标对象intCopyObj中属性List<Integer> 会存储三个String类型的值,如下:
但是下一步遍历的时候会报错,String不能转换为Integer,如下图:
原因:这就是因为泛型在编译期有效,在运行期擦除了,可以通过反射赋值而不受泛型限制,但是后面的调用运行期会报错;具体原因可以看第一部分的代码注释;
带着疑问去思考,然后串联,进而归纳总结,不断追问自己,进行自我辩证,像侦查嫌疑案件一样看待技术问题,漆黑的街道,你我一起寻找线索,你就是技术界大侦探福尔摩斯