这个是Mark Allen Weiss写的 数据结构与问题求解 第四版上面的源程序private Type[] theItems;//当前数组
private int size;//实际大小public boolean add(Type x){
   if(theItems.length==size){//数组容量满
       Type[] old = theItems;
       theItems = (Type[]) new Object[size*2+1];//这行怎么都不理解,编译能通过是因为类型擦除,但是运行
                                                 //的时候假如类型参数是String,Object[]如何强转成String[]???
       for(int i=0;i<size;i++)
           theItems[i] = old[i];//循环复制元素
   }
   theItems[size++] = x;//插入元素
   return true;}问题1:注释行的问题
问题2:因为new Type[size*2+1]语法不通过,因此还有其他方法扩展泛型数组的容量么?

解决方案 »

  1.   

    泛型一般用单个的大写字母,你这代码我看着眼晕。即然你知道擦除那就好办多了: ---- "运行的时候假如类型参数是String,Object[]如何强转成String[]"答桉很简单:---- 运行的时候不存在"类型参数是String"这个问题,类型参数编译之后都是Object,类型检查在编译时已经完成,然后擦除了。
      theItems = (Type[]) new Object[size*2+1]; 
      // 編譯之後: theItems = (Object[]) new Object[size*2+1];泛型的意义在于"编译时"。
      

  2.   

    问题2:因为new Type[size*2+1]语法不通过,因此还有其他方法扩展泛型数组的容量么?
      // reflection:
      theItems = (Type[])Arrays.newInstance(Object.class, size*2+1);
    另,这种使用一般是用在封装得很好的泛型类或泛型方法的内部,除此之外,尽量不要把数组和泛型混用,因为数组的特性天生是与"编译时类型安全"有些冲突的。
      

  3.   

    楼上写错了,是 Array.newInstance() 不是 Arrays.newInstance()
      

  4.   


    楼主这里的 Type 如果写成 T ,你还有什么疑问么?
      

  5.   

    假如我主楼里面写的类叫做MyArrayList,那在运行的时候如果泛型参数不会被String替换,那么MyArrayList泛型参数都是Object,因此即使我 MyArrayList<String> list = new MyArrayList<String>(),MyArrayList内部还是不知道类型参数是String而是只知道Object对吧?
    但是Java标准库List<String> list = new ArrayList<String>(); 然后调用List的内部方法get(i)可以直接得到不需要强制转换的String,这个不是矛盾么。
    数组的特性天生是与"编译时类型安全"有些冲突的? 这个。有点不理解。数组为嘛类型不安全
      

  6.   

    内部数组是Object数组,而不是泛型数组,如果是泛型数组,在初始化时需要传入泛型的Class,比如
    class UserList<T> {
        T[] elements; //泛型数组
        Class<T> clazz;
        int size;    public UserList(Class<T> clazz) { //需要传入泛型Class类型
            this.clazz = clazz;
            elements = (T[])Array.newInstance(clazz, 20); //default capacity 20
        }    //这样的话toArray可以直接返回 elements
    }//生成实例
    UserList<String> ul = new UserList<String>(String.class); //需要传入Class
    否则,内部数组应该使用Object数组,这就是为什么List的toArray方法需要参数T[](其实用Class<T>类型也可以)LZ可以研究一下java的ArrayList之类的源码
      

  7.   

    但是Java标准库List<String> list = new ArrayList<String>(); 然后调用List的内部方法get(i)可以直接得到不需要强制转换的String,如果内部是Object型数组这个不是矛盾么。
      

  8.   


    ArrayList的get(i)方法内部里做了转换了,LZ可以自己看源码
    return (E)elementData[index]; 
      

  9.   


    然后调用List的内部方法get(i)可以直接得到不需要强制转换的String你看到的String str = list.get(i);是编译以前的代码,实际编译以后是这样的:String str = (String)list.get(i);这就是 Java 泛型的工作原理,也就是所谓的"类型释放"。所有 Type 的地方,都是 Object。
      

  10.   

    强制类型转换仍然是存在的,使用泛型时,强制类型转换自动完成,并且保证只要使用正确编译通过,那么转换类型时一定不会抛出 ClassCastException。这里的重点在于"编译通过"。见一楼最后一句话: Java 泛型的意义在于,且仅在于,编译时。Java 泛型就是 "通过编译时的类型检查来保证运行时类型安全" 的机制。
      

  11.   

    编译时因为擦除我能完全理解,正如您说的-----所有 Type 的地方,都是 Object。我的意思是运行的时候,最关键是运行,当我使用这个类生成一个对象的时候,类型参数应该被定义的类型取代的吧,比如:MyArrayList<String> list = new MyArrayList<String>()中,全部类型参数应该被String替代吧,java在编译的时候擦除类型那么如何再识别这些定义的类型呢。希望您百忙中再帮我下看下,谢谢
      

  12.   


    不好意思,很久没上论坛了。MyArrayList<String> list = new MyArrayList<String>()中,没有识别,就是Object但是下面的代码:
    String str = list.get(0);会被编译器翻译成String str = (String)list.get(0);来编译,同样的:for(String str : list) { 
      // ... 
    }// 翻译成 ->
    for(Iterator<String> it=list.iterator(); it.hasNext();) {
      String str = it.next();
      // ...
    }// 翻译成 ->
    for(Iterator it=list.iterator(); it.hasNext();) {
      String str = (String)it.next();
      // ...
    }
    在上述翻译的强制类型转换处,实际的类型信息被保存到了运行时。而假如编译的时候顺利通过且没有警告的话,这里的强制类型转换就能确保成功。
      

  13.   


    但即使按照您写的说法,您给的例子原始就是String所以能够强制转换,但我主贴里面是
    theItems = (Type[]) new Object[size*2+1];运行的时候,我的原始类型是Object[]型,强制转换成Type[],这个也不行吧。
    唉不理解啊不理解啊。
    写了挺多泛型类了。还是把他们都记住吧。汗。分都给您了。谢谢了。
      

  14.   

    /**
     * 泛型代码
     * 
     * @date   20/09/2012
     */
    public class SafeArray<E> {
      
      public static void main(String[] args) {
        
        SafeArray<String> array = new SafeArray<String>(10);
        array.add("asdf");
        
        String str = array.get(0);
        System.out.println(str);
      }
      
      private E[] items;
      private int size;
      public SafeArray(int capacity) {
        
        if( capacity <= 0 )
          throw new IllegalArgumentException();
        
        items = (E[])new Object[capacity];
        size = 0;
      }
      
      public boolean add(E item) {
        
        if (items.length == size) {
          
          E[] old = items;
          items = (E[])new Object[size * 2 + 1];
          System.arraycopy(old, 0, items, 0, old.length);
        }
        items[size] = item;
        size++;
        return true;
      }
      
      public E get(int index) {
        
        if( index < 0 || index >= items.length )
          throw new IndexOutOfBoundsException();
        
        return index >= size ? null : items[index];
      }
    }
    /**
     * 擦除后的代码(编译后的字节码与上面的泛型代码编译后相等)。
     * 
     * @date   20/09/2012
     */
    public class SafeArray {
      
      public static void main(String[] args) {
        
        SafeArray array = new SafeArray(10);
        array.add("asdf");
        
        String str = (String)array.get(0);
        System.out.println(str);
      }
      
      private Object[] items;
      private int size;
      public SafeArray(int capacity) {
        
        if( capacity <= 0 )
          throw new IllegalArgumentException();
        
        items = (Object[])new Object[capacity];
        size = 0;
      }
      
      public boolean add(Object item) {
        
        if (items.length == size) {
          
          Object[] old = items;
          items = (Object[])new Object[size * 2 + 1];
          System.arraycopy(old, 0, items, 0, old.length);
        }
        items[size] = item;
        size++;
        return true;
      }
      
      public Object get(int index) {
        
        if( index < 0 || index >= items.length )
          throw new IndexOutOfBoundsException();
        
        return index >= size ? null : items[index];
      }
    }
      

  15.   


    总结:在泛型定义的作用范围(类或方法)内,类型擦除后泛型类型声明会被 Object 代替;而在应用代码中(声明了实际类型的地方),类型擦除后会自动添加必要的强制类型转换。