Java数组 强制类型转换

2022-10-30 14:39:44 浏览数 (2)

数组的强制类型转换

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

数组的强制类型转换

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

例如:

代码语言:javascript复制
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数组的!!!

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

先上代码:

代码语言:javascript复制
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的三参数重载方法:

代码语言:javascript复制
class ArrayList {
	... ...
	public Object[] toArray() {
    	return Arrays.copyOf(elementData, size);
	}
}
代码语言:javascript复制
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数组。如果这样的话,应该会调用?:表达式的第二个代码:

代码语言:javascript复制
			: (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类型了!那是什么时候变的呢?我们来到了它的构造方法:

代码语言:javascript复制
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()方法!!

0 人点赞