集合框架中经常会使用泛型指定集合中所存放元素的类型,保证集合的统一性,从集合中取出元素的时候也避免了类型强制转换的操作,所以我们使用常规的方式来往集合中存放元素的时候,如果指定泛型,那么我们只能向集合内添加泛型类型的对象,如果不指定泛型,那么可以往集合中添加任何类型的对象,因为此时默认元素是Object类的对象,取出时也需要类型强制转换,就如下面代码:

 ArrayList list = new ArrayList();
list.add(1);
list.add("s"); //插入的都是Object的对象类型
System.out.println(list); ArrayList<String> list1 = new ArrayList<String>();
list1.add("s");
list1.add(2); //这是错误的

  这就可以看出泛型的区别,最后一行代码会被编译器报错,下面分别获取list和list1的类类型,并进行比较:

 Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1 == c2);

  因为list和list1属于两个不同的对象,由此我们推断c1和c2也是不相等的两个类类型,但实际上结果输出true,因为反射获取到类类型相当于字节码的执行阶段,那么c1和c2肯定属于执行阶段的比较,所以我们得到结论:编译之后集合的泛型是去泛型化的,所有的集合类的类类型都相等,泛型就不存在了,泛型只是在编译的时候约束元素的类型,只在编译阶段有效,所以我们可以利用反射的原理,绕过编译,让list1也可以存放不同类型的元素:

         try {
Method m = c2.getMethod("add", Object.class);
m.invoke(list1, 100); //利用反射,在运行阶段执行从而绕过编译的操作
System.out.println(list1.size());
System.out.println(list1);
//不能用foreach来遍历
//用iterator遍历
Iterator it = list1.iterator();
while(it.hasNext()) {
Object obj1 = it.next();
System.out.println(obj1);
}
//用for遍历
for(int i = 0;i < list1.size();i++) {
Object obj2 = list1.get(i);
System.out.println(obj2);
}
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

  上面代码通过getMothod方法获得方法对象,然后通过invoke方法来执行方法,这样就可以在带有泛型的集合中存放不同的元素,这样就利用反射绕过了编译的限制;因为无法确定指定方法是否存在,因此需要抛出异常;遍历的时候我们可以使用iterator迭代器或者for循环进行遍历,但是因为类型不一致的原因,所以不能用foreach进行遍历

通过Java反射来理解泛型的本质的更多相关文章

  1. Java反射的理解(六)-- 通过反射了解集合泛型的本质

    Java反射的理解(六)-- 通过反射了解集合泛型的本质 上述写了那么多,我们可能会有个疑问,为什么要用反射,步骤比我们常规的加载类操作复杂多了,别急,这个问题我最后才解答,我们先来了解集合泛型的本质 ...

  2. java反射--通过反射了解集合泛型的本质

    通过Class,Method来认识泛型的本质 package com.reflect; import java.lang.reflect.Method; import java.util.ArrayL ...

  3. [Java反射基础四]通过反射了解集合泛型的本质

    本文接上文"方法反射的基本操作",利用反射了解下java集合中泛型的本质 1.初始化两个集合,一个使用泛型,一个不使用 ArrayList list1 = new ArrayLis ...

  4. Java基础 -- 深入理解泛型

    一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类.如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大. 而泛型很好的解决了这个问题,这也是Java SE5的重大 ...

  5. Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除问题

    在开发时,遇到了下面这条语句,不懂,然习之. private List<MyZhuiHaoDetailModel> listLottery = new ArrayList<MyZhu ...

  6. (转)JAVA反射机制理解

    JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们. 理论的东东太多也没 ...

  7. java反射的理解与应用(某大神博客中看到的博文,写的真的太好了,果断转载作为笔记)

    原文地址:http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html#undefined 一.什么是反射机制 简单的来说,反射机制指的是程序 ...

  8. Java 反射的理解

    反射反射,程序员的快乐,今天你快乐了吗?如果你不快乐,没关系,接下来让你快乐起来! 一.什么是反射? 通过百度百科我们可以知道,Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...

  9. java通过反射了解集合泛型的本质

随机推荐

  1. MyEclipse10中导入的jquery文件报错(出现红叉叉,提示语法错误)

    为了做一个页面特效,导入了一个jQuery文件,怎想,myeclipse竟然报错说是语法错误,但是这个js文件我是从官网上下载的,不应该出错才对,百度谷歌之后终于找到了解决办法: 选中报错的js文件, ...

  2. groovy-输入输出

    Groovy为I/O提供了一系列的helper methods ,所有的这些方法都适用于标准的 Java Reader/Writer ,InputStream/OutputStream 和File 以 ...

  3. Linux 内核通知链机制的原理及实现

    一.概念: 大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子 系统,Linux内核提供了通知链的机制.通 ...

  4. vs配置

    每次遇到vs配置都要让我头疼一段时间,对于某些不太清楚,有时自己试着配置,能运行起来就行,下次又忘了咋陪的了,其中配置的东西真心多. 1.输出目录这样配置../../Bin/Server/ 这个路径是 ...

  5. Conjugate prior relationships

    Conjugate prior relationships The following diagram summarizes conjugate prior relationships for a n ...

  6. 锋利的jQuery-4--阻止事件冒泡和阻止默认行为

    阻止事件冒泡: 如果嵌套元素分别有自己的click事件,当点击内层元素时外层元素的事件也会被触发. $("span").bind("click", functi ...

  7. WAF绕过的技巧

    研究过国内外的waf.分享一些绝技. 一些大家都了解的技巧如:/*!*/,SELECT[0x09,0x0A-0x0D,0x20,0xA0]xx FROM 不再重新提及. 以下以Mysql为例讲述这些技 ...

  8. C# 三种实现抖屏的方式

    //int a = -2; //this.BringToFront(); //for (int i = 0; i < 20; i++) //{ // a = -a; // this.Locati ...

  9. svn命令在linux下的使用

    svn命令在linux下的使用 SVN软件版本管理 三 12th, 2008 转载本站文章请注明,转载自:扶凯[[url]http://www.php-oa.com[/url]] 本文链接: [url ...

  10. MVC中html转义问题(直接输出html的方法)

    MVC中如果用@string(string是包含html代码的字符串)形式输出字符串,那么对应的html标签会自动转义,如果想直接输出html可用以下方法: @(new HtmlString( &qu ...