A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黄玉昆 黑马帝   /  2013-3-28 12:05  /  1233 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 黄玉昆 于 2013-3-28 12:52 编辑

在18届交流区中,我看到过有这么几个关于集合反射的问题,今天再次试验了一下,也查看了相关的文档,有点小心得,和大家分享一下。
先看个例子吧:
一共有三个:
第一个是限定为Integer类型:
  1. package cn.conpany.test.reflect;

  2. import java.lang.reflect.InvocationTargetException;
  3. import java.util.ArrayList;
  4. import java.util.Collection;

  5.         public class RefectColl {
  6.             public static void main(String[] args) throws Exception {
  7.                    
  8.                     //定义为Integer类型的集合,此时只能加入Integer类型
  9.                     ArrayList<Integer> list = new ArrayList<Integer>();
  10.                     list.add(0);
  11.                    
  12.                     //加入其它类型,需要通过反射跳过编译器,必须用Object,这里会记录下类型
  13.                 list.getClass().getMethod("add", Object.class).invoke(list, "ssss");
  14.                 System.out.println("size:" + list.size());//2
  15.                 
  16.                 //验证get方法返回类型,只要是返回的String类型,都需强转
  17.                 System.out.println("get(0)返回类型:" + list.get(0).getClass().getName());//java.lang.Integer--->原始类型是Integer集合
  18.                 System.out.println("get(1)返回类型:" + ((Object)list.get(1)).getClass().getName());//java.lang.String
  19.                 
  20.                 //集合原始类型为Integer类型集合,无需强转为Object类,可直接获取
  21.                 System.out.println("get(0)值:" + list.get(0));//0
  22.                 System.out.println("get(1)值:" + list.get(1));//ssss
  23.             }
  24.         }
复制代码
第二种为String类型:
  1. package cn.conpany.test.reflect;

  2. import java.lang.reflect.InvocationTargetException;
  3. import java.util.ArrayList;
  4. import java.util.Collection;

  5. public class RefectColl2 {
  6.     public static void main(String[] args) throws Exception {
  7.            
  8.             //定义为String类型的集合,此时只能加入String类型
  9.             ArrayList<String> list = new ArrayList<String>();
  10.             list.add("abc");
  11.            
  12.            
  13.            
  14.             //加入其它类型,需要通过反射跳过编译器,必须用Object,这里会记录下类型
  15.             list.getClass().getMethod("add", Object.class).invoke(list, new Integer(123));
  16.             list.getClass().getMethod("add", Object.class).invoke(list, 124);
  17.             list.getClass().getMethod("add", Object.class).invoke(list, new Persont("ZS",20));

  18.             //这个size方法与集合定义的类型无关
  19.             System.out.println("size:" + list.size());//4
  20.            
  21.             //验证get方法返回的类型,只要是返回的String类型,都需强转
  22.             System.out.println("get(0)返回类型:" + list.get(0).getClass().getName());//get(0)返回类型:java.lang.String--->原始类型是String集合
  23.             System.out.println("get(1)返回类型:" + ((Object)list.get(1)).getClass().getName());//get(1)返回类型:java.lang.Integer
  24.             System.out.println("get(2)返回类型:" + ((Object)list.get(2)).getClass().getName());//get(2)返回类型:java.lang.Integer
  25.             System.out.println("get(3)返回类型:" + ((Object)list.get(3)).getClass().getName());//get(3)返回类型:cn.conpany.test.reflect.Persont
  26.            
  27.             //可直接获取编译器前的原类型,即String类型
  28.             System.out.println("get(0)值:" + list.get(0));//abc
  29.             //集合的原始类型定义为String集合类型,所以,需要先强转为Object类,才能获取,否则编译失败
  30.             System.out.println("get(1)值:" + (Object)list.get(1));//123
  31.         System.out.println("get(2)值:" + (Object)list.get(2));//124
  32.         System.out.println("get(3)值:" + (Object)list.get(3));//name:ZS,age:20
  33.     }
  34. }
复制代码
第三种为Persont类型
  1. //定义Persont类
  2. class Persont{
  3.         private String name;
  4.         private int age;
  5.         public Persont(String name, int age) {
  6.                 this.name = name;
  7.                 this.age = age;
  8.         }
  9.                
  10.                 public String toString(){
  11.                         return "name:" + name + ",age:" + age;
  12.                 }
  13.         }
复制代码
  1. package cn.conpany.test.reflect;

  2. import java.lang.reflect.InvocationTargetException;
  3. import java.util.ArrayList;
  4. import java.util.Collection;

  5. public class RefectColl3 {
  6.     public static void main(String[] args) throws Exception {
  7.            
  8.             //定义为String类型的集合,此时只能加入String类型
  9.             ArrayList<Persont> list = new ArrayList<Persont>();
  10.             list.add(new Persont("LS",27));
  11.            
  12.            
  13.             //加入其它类型,需要通过反射跳过编译器,必须用Object,这里会记录下类型
  14.             list.getClass().getMethod("add", Object.class).invoke(list, new Integer(123));
  15.             list.getClass().getMethod("add", Object.class).invoke(list, 124);
  16.             list.getClass().getMethod("add", Object.class).invoke(list, new Persont("ZS",20));

  17.             //这个size方法与集合定义的类型无关
  18.             System.out.println(list.size());//4
  19.            
  20.             //验证get方法返回的类型,只要是返回的String类型,都需强转
  21.             System.out.println("get(0)返回类型:" + list.get(0).getClass().getName());//cn.conpany.test.reflect.Persont--->原始类型是Persont集合
  22.             System.out.println("get(1)返回类型:" + ((Object)list.get(1)).getClass().getName());//java.lang.Integer
  23.             System.out.println("get(2)返回类型:" + ((Object)list.get(2)).getClass().getName());//java.lang.Integer
  24.             System.out.println("get(3)返回类型:" + ((Object)list.get(3)).getClass().getName());//cn.conpany.test.reflect.Persont
  25.            
  26.             //可直接获取跳过编译器前的原类型,即String类型
  27.             System.out.println("get(0)值:" + list.get(0));//name:LS,age:27
  28.             //集合的原始类型定义的是Persont集合类型,无需强转,直接获取
  29.             System.out.println("get(1)值:" + list.get(1));//123
  30.         System.out.println("get(2):" + list.get(2));//124
  31.         System.out.println("get(3):" + list.get(3));//name:ZS,age:20
  32.     }
  33. }
复制代码
结论:
代码很多,但是你认真看了,就会发现一个特别有趣的现象:
1、查看ArrayList的API文档,你就可以发现,其中的ArrayList是这样定义的:ArrayList<E>,而其中的add方法定义为:boolean add(E e),你是不是发现了什么,没错,即使反射将类型擦出了,其实反射是脆弱的,即使擦出了集合的类型信息,但是其中的方法可能还会保留原始限定的类型,所以,在加入的时候,仍需要用Object.class。
2、对于返回类型与集合无法的,如size这个方法,无需强转,直接获取。
3、很重要的一点:除了String类型以外的其他类型(包括自定义类型),无需强转,可以直接使用相应集合中的方法。如上面的get()方法。我个人理解,与集合有关的方法,如get方法只有在你添加进元素时,才能调用,所以,即使get定义为:E get(int index),也无需强转。这里,String类型除外。
4、但是对于String类型呢?作为String类型的值,如果添加入限定为非String集合中,那么就需要强转,究其原因,我只能说String是比较特殊的一个类,它有如下特性:被定义为final,而且其值是存在了常量池中,并且可以将任意类型值通过字符串打印。基于如此特殊的类,那么,它必然也有某些特性。这里,我会继续探究,如果谁有个人见解,请多指教,谢谢

点评

好帖  发表于 2013-3-28 15:00

评分

参与人数 1黑马币 +12 收起 理由
曹睿翔 + 12 赞一个!

查看全部评分

1 个回复

正序浏览
有点意思啊,不过实际操作的时候eclipse会提示,嘿嘿
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马