论坛首页 Java企业应用论坛

泛型理解上的一个问题

浏览 10388 次
该帖已经被评为隐藏帖
作者 正文
   发表时间:2010-11-08  
(1)对于arr1
就相当于Object o = arr1.get(0);
(2)对于arr2
就相当于String obj2 = arr2.get(0);(报错)
0 请登录后投票
   发表时间:2010-11-08   最后修改:2010-11-08
原来是System.out.println();造成的,以后遇到问题,一步步调试很是很必要的
再说,ArrayList里存放数据用的Object数组不是T数组。。
0 请登录后投票
   发表时间:2010-11-08  
// Decompiled by DJ v3.6.6.79 Copyright 2004 Atanas Neshkov  Date: 2010-11-08 9:27:39
// Home Page : http://members.fortunecity.com/neshkov/dj.html  - Check often for new version!
// Decompiler options: packimports(3) 
// Source File Name:   Test.java

package com.paic;

import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class Test
{

    public Test()
    {
    }

    public static void main(String args[])
        throws Exception
    {
        ArrayList arr1 = new ArrayList();
        ArrayList arr2 = new ArrayList();
        System.out.println(arr1.getClass() == arr2.getClass());
        arr1.add(Integer.valueOf(55));
        arr1.getClass().getMethod("add", new Class[] {
            java/lang/Object
        }).invoke(arr1, new Object[] {
            "dodo"
        });
        System.out.println(arr1.get(1));
        arr2.add("why");
        arr2.getClass().getMethod("add", new Class[] {
            java/lang/Object
        }).invoke(arr2, new Object[] {
            Integer.valueOf(33)
        });
        System.out.println((String)arr2.get(1)); //看这一行
    }
}


这怎么能是System.out.println()的错误呢?
之前朋友给的反编译的代码我觉得就可以完全解释了。 编译后的代码是:
System.out.println((String)arr2.get(1)); //看这一行
这句话Run的时候肯定就ClassCastException了。

虽然你在源码里面是写 arr2.get(1), 但是因为泛型的关系,编译后的代码给做了强制类型转换了。。。
0 请登录后投票
   发表时间:2010-11-08   最后修改:2010-11-08
悲剧了 写道
请帮忙解释下这个泛型问题,具体逻辑我都下在代码注释里面了
public class Test01 {
	public static void main(String[] args) throws Exception{
		ArrayList<Integer> arr1=new ArrayList<Integer>();
		ArrayList<String> arr2=new ArrayList<String>();
		//下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的
		System.out.println(arr1.getClass()==arr2.getClass());
		//那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串
		arr1.add(55);
		arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo");
		System.out.println(arr1.get(1));
		//既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException
		arr2.add("why");
		arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33);
		System.out.println(arr2.get(1));
	}

}



给你个终结贴吧:

请查看如下我修改的代码:

public class Test01 {   
    public static void main(String[] args) throws Exception{   
        ArrayList<Integer> arr1=new ArrayList<Integer>();   
        ArrayList<String> arr2=new ArrayList<String>();   
        //下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的   
        System.out.println(arr1.getClass()==arr2.getClass());   
        //那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串   
        arr1.add(55);   
        arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo");   
        System.out.println(arr1.get(1));   
        //既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException   
        arr2.add("why");
        arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33);   
//        System.out.println(arr2.get(1));//这里其实和add的道理一样,还是没有绕过编译时泛型的检查
        //如果你add的时候用反射绕过了,get的时候为什么不绕呢??
        
        //arr1之所以可以是因为编译器自动将Integer看作Object自动调用了println(Object obj)方法,其实还是没有
        //绕过编译时的泛型定义,只是有对应的println方法罢了,还是检查了<Integer>了的。pringln的时候会
        //直接调用println(Object obj)
        //arr2同样会检查泛型类型,一看是<String>,那么就会找println(String s)方法,因为存在这个方法,所以
        //直接调用了println(String s)该方法,这就是为什么arr2的out.pringln会调用打印String的方法,而不是
        //打印Object的方法了,而调用String的pringln的方法必然会作(String)强转了。
        
        //下面是get的时候也通过反射来绕过编译时泛型检查,肯定是没问题的。
        //呵呵,没有任何矛盾,不明白请跟帖,我回回复。
        Object obj1=arr2.getClass().getMethod("get", int.class).invoke(arr2, 1);
        System.out.println(obj1);
        
    }   
  
}  



//呵呵,没有任何矛盾,不明白请跟帖,我回回复。
1 请登录后投票
   发表时间:2010-11-08  
只能说你们的回答太肤浅了。
ArrayList<Integer> arr1 =new ArrayList<Integer>();
		arr1.add(11);
		System.out.println(arr1.getClass());

多说无益,自己看看这个之后就知道是怎么回事了。
望大虾们,回贴时注意份量,不要影响我们这些菜鸟。谢谢
0 请登录后投票
   发表时间:2010-11-08  
coffeesweet 写道
悲剧了 写道
请帮忙解释下这个泛型问题,具体逻辑我都下在代码注释里面了
public class Test01 {
	public static void main(String[] args) throws Exception{
		ArrayList<Integer> arr1=new ArrayList<Integer>();
		ArrayList<String> arr2=new ArrayList<String>();
		//下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的
		System.out.println(arr1.getClass()==arr2.getClass());
		//那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串
		arr1.add(55);
		arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo");
		System.out.println(arr1.get(1));
		//既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException
		arr2.add("why");
		arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33);
		System.out.println(arr2.get(1));
	}

}



给你个终结贴吧:

请查看如下我修改的代码:

public class Test01 {   
    public static void main(String[] args) throws Exception{   
        ArrayList<Integer> arr1=new ArrayList<Integer>();   
        ArrayList<String> arr2=new ArrayList<String>();   
        //下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的   
        System.out.println(arr1.getClass()==arr2.getClass());   
        //那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串   
        arr1.add(55);   
        arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo");   
        System.out.println(arr1.get(1));   
        //既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException   
        arr2.add("why");
        arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33);   
//        System.out.println(arr2.get(1));//这里其实和add的道理一样,还是没有绕过编译时泛型的检查
        //如果你add的时候用反射绕过了,get的时候为什么不绕呢??
        
        //arr1之所以可以是因为编译器自动将Integer看作Object自动调用了println(Object obj)方法,其实还是没有
        //绕过编译时的泛型定义,只是有对应的println方法罢了,还是检查了<Integer>了的。pringln的时候会
        //直接调用println(Object obj)
        //arr2同样会检查泛型类型,一看是<String>,那么就会找println(String s)方法,因为存在这个方法,所以
        //直接调用了println(String s)该方法,这就是为什么arr2的out.pringln会调用打印String的方法,而不是
        //打印Object的方法了,而调用String的pringln的方法必然会作(String)强转了。
        
        //下面是get的时候也通过反射来绕过编译时泛型检查,肯定是没问题的。
        //呵呵,没有任何矛盾,不明白请跟帖,我回回复。
        Object obj1=arr2.getClass().getMethod("get", int.class).invoke(arr2, 1);
        System.out.println(obj1);
        
    }   
  
}  



//呵呵,没有任何矛盾,不明白请跟帖,我回回复。

谢谢,分析得很好很清晰!
0 请登录后投票
   发表时间:2010-11-08  
麻烦大家去看一看。
ArrayList<String> arr1 = new ArrayList<String>();
ArrayList<Integer> arr2 = new ArrayList<Integer>();
System.out.println(arr1.getClass());
System.out.println(arr2.getClass());
返回的是什么?
这个问题,我想不用我多说了。
0 请登录后投票
   发表时间:2010-11-08  
擦除。。。。
0 请登录后投票
   发表时间:2010-11-09  
yunzhiyifeng 写道
这应该是一个println重载的问题,并不是反射引起的classcastexception,
System.out.println(arr1.get(1));   //此时调用的是println(Object x)的方法,看代码:
public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
},这里会显示的调用valueOf()方法,所以在print的时候,都会调用该对象自身的toString,不会出异常。而System.out.println(arr2.get(1));此时arr2.get(1)的编译类型是String,所以调用的是println(String x),此时就不会做toString的操作,直接作为了String对象,所以编译器会产生checkcast语句,看arr2.get(1)能否转换为String,而此时arr2.get(1)是Integer,做类型转换的时候便会报错。


+1

范型是在编译的时候确定的,所以调用的是println(String x)方法,抛出classcastexception
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics