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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 悟佛修道 于 2013-5-26 14:46 编辑
  1. class GenericDemo
  2. {
  3. public static void main(String[] args)
  4. {

  5. ArrayList al = new ArrayList();

  6. al.add("abc01");
  7. al.add("abc0991");
  8. al.add("abc014");

  9. //al.add(4);//al.add(new Integer(4));


  10. Iterator<String> it = al.iterator();
  11. while(it.hasNext())
  12. {
  13. String s = it.next();

  14. System.out.println(s+":"+s.length());
  15. }
  16. }
  17. }
复制代码
毕老师在讲泛型的时候,特别举了个示例那就是在集合里先是添加字符串对象后,又添加了一个整数对象al.add(4)。这时还没定义集合的泛型<string>,结果就报错了。为什么会报错呢?在讲集合的时候不是说集合与数组的区别有一点就是可以存储不同的数据类型。既然可以存储不同的类型,为什么这里存入了两种类型后就报错呢?有点不解.......

评分

参与人数 1技术分 +1 收起 理由
殇_心。 + 1

查看全部评分

8 个回复

倒序浏览
本帖最后由 徐启坤 于 2013-5-23 19:44 编辑

楼主,集合只能存放引用型对象,基本类型不能直接存
而4是int型,所以不能这样存进集合
如果想存的话,需要将基本类型包装成类
例如int型对应的Integer
char对应的Character等

评分

参与人数 1技术分 +1 收起 理由
刘胜寒 + 1

查看全部评分

回复 使用道具 举报
你加的时候应该没报错吧,是迭代的时候报错的
回复 使用道具 举报
集合是可以存不同对象的,只是你没有仔细看这段代码,这段代码中很多地方限定了对象类型为String,所以当al.add(4);时会报错,我把限定的地方标出来了①②③
  1. import java.util.ArrayList;
  2. import java.util.Iterator;

  3. class GenericDemo {
  4.         public static void main(String[] args) {

  5.                 ArrayList al = new ArrayList();

  6.                 al.add("abc01");
  7.                 al.add("abc0991");
  8.                 al.add("abc014");

  9.                 // al.add(4);//al.add(new Integer(4));

  10.                 Iterator<String> it = al.iterator();// ①这个地方的<String>限定了你的对象时string类型,要去掉

  11.                 while (it.hasNext()) {
  12.                         // ②这里再次把元素付给String类型的变量s, 去掉String s,直接打印it.next()
  13.                         String s = it.next();

  14.                         System.out.println(s + ":" + s.length());// ③括号内的.length()方法是字符串的方法,Integer对象不具备这个方法。
  15.                 }
  16.         }
  17. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
Sword + 1

查看全部评分

回复 使用道具 举报
向集合里面存储不同的类型是可以了,只是取出来对其进行操作时可能会出现安全问题。
(你上面的程序在迭代过程中,由于泛型,如果取出了Integer类型的元素怎么可能强制转换成String类型的呢?)
你可以这样想一下,如果集合里面存储了各种类型的数据的,当你取出一个元素的时候,由于没有泛型,默认的就是Object了,你首先要考虑的就是类型转换了。再进行其他的操作。在这个过程中很可能出现问题。例如你将集合中的元素都取出来,里面有String类型,和Integer类型。然后对所有元素进行相同的操作,而这其中可能就会有每一种类型根本不支持的操作(就像上面的length方法一样。)。很多时候编译时期不会报错,到了运行时期就会报错。所以就会挂了。
出现了泛型就可以解决了,一个集合中只能存储一种类型的元素。当你存储不合法的元素类型时,在编译时期就会报错。也就不存在安全问题了。而且不用对元素进行类型转换了。

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
先看集合的原理。
集合是什么?集合就是将数据封装,然后将封装好的对象进行关系.不明白?
那这样说。一个类里面可以包括N个数据和N个方法,你现在有一个数据假设是int,你想将这个int数据放进集合里,那么集合是怎么做的呢?其实集合就是在一个类的内部定义了一个int的变量,将你这个int记录了下来,你再来一个int他再重新生成一个对象,再把你这个int在它内部的成员记录下来,他还有别的属性和方法,主要是为了连接自身其它对象用的。
举个形象点的例子。
你有三个数,int a=1,b=2,c=3;你想将这三个数放进集合。假设这个集合是一个链表集合
此时集合会在内部产生一个包装类,这个包装类会自动建立三个对象,这外包装类它里有几个属性,一个是int就是用来记录你的变量的比如a,一个指向自身类的引用是记录下一个对象的。
大概简单用代码写一下就是。

假设包装类名为array

class Array
{
    Array(int num,Array next){this.num = num;this.next = next;}
        int num;
        Array next;
}

三个变量进入集合后,其实集合内的代码就是
Array ar = new Array(a,null);
ar = new Array(b,ar);
ar = new Array(c,ar);

然后将ar返回给集合记录,集合本身只记录ar就可以了,然后通过ar.next就可以一直向下找到其它的集合成员。
当然这是简单的单向链表,java中的LinkedList使用的双向是更复杂一点,我为了给你演示就只说单向的了。

从上面的例子你应该可以看的出集合的原理是什么了,其实就是把原来的数据外面再包一层数据,然后将这个新的数据之间建立相互的联系,而被包装后的新数据是一个对象,同一集合中的新包装对象必须是同一个类创建出来的,否则他们之间怎么建立联系呢?
 就像数组一样,一个6个元素的数组,你总不能让他前三个存int后三个存long吧。数组一被初始化时,就会向操作系统申请一块和这个数组大小相同的内存空间。比如数组是int有三个元素 ,那就是3*4=12个字节,int[] arr={1,2,3};执行到这句,系统就会在内存中找出一块大小大于或等于 12字节的空间,将空间的第一个地址交给arr来保管。然后arr通过每次移动4个字节的大小来找到arr数组中后面的元素位置。如果你一个数组中类型不相同,那么大小也就可能不相同,你让他怎么找?让他每次移动多少个字节去找后面的数据?int[] arr={1,2,3}; arr 移动一次就是4字节代表2了再移动一次4字节代表3了,你丫中间突然来个8字节的long 形,你让他怎么移?

 由上可知数组中的元素 必须是同一类型,同理集合中的元素 也必须是同一类型产生的对象,否则arraylist这是个java数组集合,他就不知道一次要移动多少字节。他包装新数据时也不知道要包装什么类型的,提取数据时也不知道要提出来的到底是int还是long,只有这个数据在集合一建立时就确定了,他才能正常的执行后面的内存查找工作。

 一个集合你写不写模板泛型,只要第一个元素一进去,这个集合可以添加的类型就已经被确定了。因为只要你一个元素进去,他里面那个自动包装对象就成型了。你再传一个新的类型进去,他那个包装类包装不了。如果再产生一个新的类去包装你新的数据类型,那么与之前的那个包装类就不是同一个类的对象了。大小不同先不说,他们之间根本没办法建立联系了。

就像上面写的代码一样,他包装类内部 有一个array类的引用 ,用来记录下一个对象的地址,如果你两个对象都不一样,他用什么类型去记录?当然可以用object来记录,可是这样以来,你取出来的时候你知道这个object包装类,里面包装的是哪个类型吗,

评分

参与人数 1技术分 +1 收起 理由
Sword + 1

查看全部评分

回复 使用道具 举报
风乐 中级黑马 2013-5-23 21:48:52
7#
楼主,你应该学会看异常,一般上面都会标明是哪里错的。你的代码运行结果
Exception in thread "main" java.lang.ClassCastException: java.lang.Character can
not be cast to java.lang.String
        at Test.main(Test.java:19)

显然是迭代时候出错了。借用板凳的代码

                Iterator<String> it = al.iterator();// ①这个地方的<String>限定了你的对象时string类型,要去掉
                 //因为泛型的擦除功能,<String>只用于编译检查,所以编译通过运行了就没有了,所以这里无关紧要

                while (it.hasNext()) {
                        // ②这里再次把元素付给String类型的变量s, 去掉String s,直接打印it.next()
                        //因为①处的泛型存在,所以这里编译通过,如果没有泛型则这里需强转。到这里你应该知道了吧,抛得异常就是类型转换异常
                        String s = it.next();

                        System.out.println(s + ":" + s.length());// ③括号内的.length()方法是字符串的方法,Integer对象不具备这个方法。
                }
        }
}

评分

参与人数 1技术分 +1 收起 理由
Sword + 1

查看全部评分

回复 使用道具 举报
楼主你好,如果问题以解决,请修改分类,谢谢合作。
回复 使用道具 举报
占琳 中级黑马 2013-5-24 08:00:40
9#
因为list.add()方法里面存放的是引用类型的变量,而不能直接放基本数据类型 ,如果需要放入里面 必须进行包装类型的转换 例如int要转换成为new Interger();才能运行起来 所以你list.add(4);是错误的

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马