欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java数组 强制类型转换

程序员文章站 2022-03-11 09:11:10
数组的强制类型转换数组的强制类型转换数组类型转换的问题为什么会出现在我脑海中?数组的强制类型转换最重要的是!!!最开始的时候声明的数组类型!!!最重要的是!!!最开始的时候声明的数组类型!!!最重要的是!!!最开始的时候声明的数组类型!!!例如:Object[] objects = new Object[2];Object[0] = "hello";Object[1] = "world";Object[] objects1 = {"kkkk", 3434}System.out.prin...

数组的强制类型转换

最重要的是!!!最开始的时候声明的数组类型!!!
最重要的是!!!最开始的时候声明的数组类型!!!
最重要的是!!!最开始的时候声明的数组类型!!!

例如:

Object[] objects = new Object[2];
Object[0] = "hello";
Object[1] = "world";
Object[] objects1 = {"kkkk", 3434}

System.out.println(objects.getClass());
System.out.println(objects1.getClass());
System.out.println(objects[0].getClass());
System.out.println(objects[1].getClass());
System.out.println(objects1[0].getClass());
System.out.println(objects1[1].getClass());

class [Ljava.lang.Object;
class [Ljava.lang.Object;
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.Integer
  根据实验,一开始就声明为String数组,可以在需要时自动转为Object数组,之后可以通过强制类型转换再转回String数组
  但是,如果一开始就声明为Object数组,那么,即便这个数组中存放的全部是String对象,也是不能转换为String数组的!!!

数组类型转换的问题为什么会出现在我脑海中?

先上代码:

public class Base {
    public ArrayList<String> data;
    
    public String[] getData() {
        return (String[])data.toArray();
    }
    
    public void setData(String[] data) {
        this.data = new ArrayList<String>(Arrays.asList(data));
    }
}

  遇到的问题如下:当调用setData设置好data之后,紧接着getData()将会抛出一个类型转换异常java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;提示不能将String数组强转为Object数组,这是为什么呢???明明我是String泛型的ArrayList呀,怎么一toArray()就成了Object数组了呢???而且这个Object数组为什么不能强转成String数组呢?我自己用String数组转换成Object数组之后,是可以转回String数组的呀,为什么这里就转不回去,而且报错了呢??????

  带着问题的 我 和 源码 展开了“深入”交流
  参照源代码的时候发现,首先,Arrays.asList(data)依然返回的是泛型,也就应该是String[]。因此,上述ArrayList的那个构造方法,传入参数时,应该是String[]。

  这就神奇了,既然我参数传入的时候还是String数组,为什么data.toArray();就成了Object数组了呢???难道是data.toArray()这个方法在搞鬼??
  带着疑问,继续阅读源码,发现这个无参的toArray()方法转向了Arrays类的静态方法Arrays.copyOf(elementData, size);,之后又转向了copyOf的三参数重载方法:

class ArrayList {
	... ...
	public Object[] toArray() {
    	return Arrays.copyOf(elementData, size);
	}
}
class Arrays {
	... ...
	public static <T> T[] copyOf(T[] original, int newLength) {
        	return (T[]) copyOf(original, newLength, original.getClass());
	}
	
	... ...
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
}

  那么问题来了,这个作为参数传入的ArrayList的实例域elementData实际上是什么类型的数组呢?这个3个参数的copyOf又干了什么呢???
  首先,看看这个三参数copyOf()函数干了什么:我们不妨假设elementData.getClass()依然是String数组。如果这样的话,应该会调用?:表达式的第二个代码:

			: (T[]) Array.newInstance(newType.getComponentType(), newLength);

  Array.newInstance()返回的是Object引用类型,并最终导向native代码。虽然我不清楚它做了什么,但是有两点可以确定:

  1. 源代码既然在强转的时候没有报错,说明该方法的返回的实际对象一定是T子类的数组。而T类型是什么呢?因为假设传入的是String数组的Class对象,且这里String除了Object之外没有超类了,所以T必为Object类型;
  2. 很显然冒号左侧才是新建了一个Object数组,那冒号右面猜测应该是建立了一个泛型数组,但是暂时不确定。
  3. 在返回到二参数copyOf()方法中的时候,这里的T数组我们已经假设为String数组(因为我们假设elementData是String数组),在将Array.newInstance()产生的数组强转为T数组(String数组)时没有报错,说明,Array.newInstance()产生的必然是String数组。

  也就是说,在二参数copyOf()返回时,返回类型必然和elementData是同一类型,那我们又假设elementData是String数组,最后toArray()返回就不是String数组吗???怎么之后强转会出错呢?

  那只能说明假设错了!!!!!

  那说明elementData已经不是String类型了!那是什么时候变的呢?我们来到了它的构造方法:

class ArrayList {
	......
	public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
}

  看到这个方法的第4、5行,已经当场气死~原来在构造方法的时候,就已经将不是Object数组的数组转成了Object数组,并存放在elementData中,而无参的toArray()方法并没有对其特殊处理,直接返回了一个Object数组(虽然里面元素仍然是String)。

  所以,如果要返回泛型数组,该怎么办呢?
  答案是:调用带参的toArray()方法!!

本文地址:https://blog.csdn.net/u013009552/article/details/107367628