Java中一个运用反射解决问题例子+思考

Java中一个运用反射解决问题例子+思考


题目:对于给定的ArrayList的一个对象,通过什么办法可以在集合中添加一个字符串数据?

1.如果只给ArrayList的一个对象,我们可以轻松地实现存放各种类型的数据,只不过唯一的缺点就是不安全(为什么并不安全,这也是jdk1.5出现泛型机制的原因,下面会有复习回顾)。

    ArrayList array = new ArrayList();
    array.add("hello");
    array.add(10);//自动装箱,因为集合里面不能存放基本简单数据类型

为了解决这个问题,我们先回顾一下泛型。

泛型:在JDK1.5以后出现的新特性,用于解决安全问题,是一个安全机制。

好处:
1.将运行时期 出现的问题ClassCastException(叫做类型转换异常),转移到了编译时期。
方便于程序员解决问题,让运行时期问题减少,保证了安全。
2.避免了强制类型转换。

    //Demo1:不加泛型
    ArrayList al=new ArrayList();
    al.add("abc01");
    al.add("abc0991");
    al.add("abc014");
    al.add(4);

    Iterator it=al.iterator();
    while(it.hasNext()){
        String s=(String)it.next();//安全问题发生的地方
        System.out.println(s+":"+s.length());
    }

分析:上面的代码编译(javac…)期间是不会出现任何问题的,也就是报一个安全问题的警告,运行(java…)期间程序则崩溃,引发了ClassCastException。很明显,这里所说的安全问题就是编译期间发现不了的异常:Integer无法转成String。

所以:泛型机制引入其实就是给编译器看的,实际运行中,还是根据class文件对象生成ArrayList的实例,进而调用源码的方法运行的。

    //使用泛型解决上述问题
    ArrayList<String> al=new ArrayList<String>();
    al.add("abc01");
    al.add("abc0991");
    al.add("abc014");
    //al.add(4);//编译期间出错,我们需要注释掉

    Iterator<String> it=al.iterator();
    while(it.hasNext()){
        String s=it.next();//避免了类型的强转
        System.out.println(s+":"+s.length());
    }

    //验证泛型就是给编译器看的这个说法,利用反编译工具分析上面这个代码的.class文件,下面就是反编译后的代码。
    ArrayList al=new ArrayList();
    al.add("abc01");
    al.add("abc0991");
    al.add("abc014");

    Iterator it=al.iterator();
    while(it.hasNext()){
        String s=(String)it.next();
        System.out.println(s+":"+s.length());
    }

其实原因很简单,ArrayList的源码以及相关方法(比如add方法),本质上操作类型就是Object,public boolean add(E e)。只不过泛型的引入将E在编译期间进行了限定而已,而实际运行期间中通过class字节码文件生成的class对象还是调用add(E e),是可以接收其他类型的数据进行添加,因为一切对象类型都可以看成Object。


分析到现在,我们大概已经想到了如何解决问题了,上面的小总结告诉我们,泛型仅仅是让编译器看的,实际运行中还是源码ArrayList类的中add方法,所以我们可以通过反射机制,通过class字节码文件对象调用add(E e),指定Object类型,实现字符串在运行期间的添加,而且不会在编译时期因为泛型的原因报错。

public class ArrayListDemo {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> array = new ArrayList();
        array.add(10);

        Class c = array.getClass(); // 集合ArrayList的class文件对象

        // public Method getMethod(String name,Class<?>... parameterTypes)
        // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
        Method m = c.getMethod("add", Object.class);

        // public Object invoke(Object obj,Object... args)
        // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
        m.invoke(array, "java");// 调用array的add方法,传入的值是hello

        array.add(12);

        System.out.println(array);//结果就是[10, java, 12]
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值