我不明白为什么会发生这种ClassCastException

时间:2012-01-05 16:22:23

标签: java android serialization android-intent parcelable

// Application ...
Intent i = new Intent();
i.putExtra(EXTRA_FILE_UPLOAD_URIS, mGalleryAdapter.getItems()); 

Uri[] getItems() { return mItems; }

// Service ...
intent.getParcelableArrayExtra(EXTRA_FILE_UPLOAD_URIS); //works, returns Parcelable[]
Uri[] uris = (Uri[])intent.getParcelableArrayExtra(EXTRA_FILE_UPLOAD_URIS);
// ... Breaks with ClassCastException

Uri[]Uri时,为什么投降到Parcelable会中断?

5 个答案:

答案 0 :(得分:28)

使用此方法,它适合我。

Parcelable[] ps = getIntent().getParcelableArrayExtra();
Uri[] uri = new Uri[ps.length];
System.arraycopy(ps, 0, uri, 0, ps.length);

答案 1 :(得分:21)

不幸的是,Java无法对数组进行强制转换。您将不得不迭代您的数组并单独转换每个对象。

原因是类型为Safety,JVM无法确保数组的内容可以转换为Uri,而不必通过它们进行迭代,这就是为什么你必须迭代它们并抛出它们个别。

基本上因为Parcelable可以被其他对象继承,所以不能保证数组只包含Uri个对象。但是,转换为超类型将起作用,因为类型安全性是可以的。

答案 2 :(得分:9)

数组具有多态行为 - 只有泛型类型没有。

也就是说,如果Uri实现Parcelable,那么

你可以说:

Parcelable[] pa = new Uri[size];
Uri[] ua = (Uri[]) pa;
你不能说:

List<Parcelable> pl = new ArrayList<Uri>();

如您所见,我们可以将pa投回Uri[]。那有什么问题呢?当您的应用程序被终止并稍后重新创建已保存的数组时,会发生此ClassCastException。重新创建时,运行时不知道它是什么类型的数组(Uri[])所以它只是创建一个Parcelable[]并将元素放入其中。因此,当您尝试将其投放到ClassCastException时,Uri[]

请注意,当进程未被终止且原始创建的数组(Uri[])在状态保存/恢复轮次之间重用时,(理论上)不会发生异常。就像改变方向一样。

我只是想说清楚为什么会这样。如果你想要一个解决方案@solo提供一个体面的解决方案。

干杯

答案 3 :(得分:0)

我认为发生的事情如下:

class Parent { }

class MaleParent extends Parent { }

class FemaleParent extends Parent { }

如果场景如上所述,那么以下内容将在运行时失败:

Parent[] parents = new FemaleParent[]{};
MaleParent[] maleParents = (MaleParent[]) parents;

以下内容不会引发异常:

Parent[] parents = new MaleParent[]{};
MaleParent[] maleParents = (MaleParent[]) parents;

答案 4 :(得分:0)

https://stackoverflow.com/a/8745966/72437https://stackoverflow.com/a/20073367/72437很好地解释了为什么会发生此类崩溃。

https://stackoverflow.com/a/14866690/72437还提供了一个示例,说明了如何解决此问题。

我想提供代码示例,以帮助更好地理解。

让我举个例子说明为什么这种事件有时会失败。

一个示例来说明为什么发生这种崩溃

package javaapplication12;

/**
 *
 * @author yccheok
 */
public class JavaApplication12 {

    public static class Parcelable {

    }

    public static class Uri extends Parcelable {

    }

    public static Parcelable[] getParcelableArrayExtraDuringLowMemoryRestoration() {    
        // The Android system has no way to know it needs to create Uri[],
        // during low memory restoration process.

        Parcelable[] parcelables = new Parcelable[3];

        for (int i=0; i<parcelables.length; i++) {
            parcelables[i] = new Uri();
        }

        return parcelables;
    }

    public static Parcelable[] getParcelableArrayExtra() {        
        // The Android system has enough information that it needs to create Uri[]

        Uri[] temp = new Uri[3];
        for (int i=0; i<temp.length; i++) {
            temp[i] = new Uri();
        }
        Parcelable[] parcelables = temp;
        return parcelables;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // OK
        {
            // true
            System.out.println(getParcelableArrayExtra() instanceof Uri[]);

            Uri[] uris = (Uri[])getParcelableArrayExtra();
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }

        // Crash!
        {
            // false
            System.out.println(getParcelableArrayExtraDuringLowMemoryRestoration() instanceof Uri[]);

            // ClassCastException.
            Uri[] uris = (Uri[])getParcelableArrayExtraDuringLowMemoryRestoration();         
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }
    }    
}

一个演示如何解决此问题的示例

package javaapplication12;

/**
 *
 * @author yccheok
 */
public class JavaApplication12 {

    public static class Parcelable {

    }

    public static class Uri extends Parcelable {

    }

    public static Parcelable[] getParcelableArrayExtraDuringLowMemoryRestoration() {    
        // The Android system has no way to know it needs to create Uri[],
        // during low memory restoration process.
        Parcelable[] parcelables = new Parcelable[3];

        for (int i=0; i<parcelables.length; i++) {
            parcelables[i] = new Uri();
        }

        return parcelables;
    }

    public static Parcelable[] getParcelableArrayExtra() {        
        // The Android system has enough information that it needs to create Uri[]
        Uri[] temp = new Uri[3];
        for (int i=0; i<temp.length; i++) {
            temp[i] = new Uri();
        }
        Parcelable[] parcelables = temp;
        return parcelables;
    }

    private static Uri[] safeCastToUris(Parcelable[] parcelables) {
        if (parcelables instanceof Uri[]) {
            return (Uri[])parcelables;
        }
        int length = parcelables.length;
        Uri[] uris = new Uri[length];
        System.arraycopy(parcelables, 0, uris, 0, length);
        return uris;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // OK
        {
            Uri[] uris = safeCastToUris(getParcelableArrayExtra());
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }

        // OK too!
        {
            Uri[] uris = safeCastToUris(getParcelableArrayExtraDuringLowMemoryRestoration());            
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }
    }    
}