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

发布于 2024-12-24 19:36:12 字数 473 浏览 2 评论 0原文

// 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

UriParcelable 时,为什么到 Uri[] 的转换会中断?

// 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

Why does the cast to Uri[] break, when Uri is Parcelable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

丢了幸福的猪 2024-12-31 19:36:12

使用这个方法,它对我有用。

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

Use this method, it work for me.

Parcelable[] ps = getIntent().getParcelableArrayExtra();
Uri[] uri = new Uri[ps.length];
System.arraycopy(ps, 0, uri, 0, ps.length);
爱的故事 2024-12-31 19:36:12

不幸的是,在Java 中没有办法像这样对数组进行强制转换。您将必须迭代数组并单独转换每个对象。

原因是类型安全,JVM 根本无法确保数组的内容可以转换为 Uri,而无需迭代它们,这就是为什么您必须迭代它们并转换它们单独。

基本上,因为 Parcelable 可以被其他对象继承,所以不能保证数组仅包含 Uri 对象。然而,转换为超类型是可行的,因为这样类型安全就可以了。

Unfortunately there is no way to cast like that for arrays in Java. You will have to iterate your array and cast each object individually.

The reason for this is type Safety, the JVM simply cannot ensure that the contents of your array can be casted to Uri, without having to iterate thru them, which is why you have to iterate them and cast them individually.

Basically because Parcelable could be inherited by other Objects, there is no guarantee that the Array contains only Uri objects. However casting to a supertype would work since then type safety would be ok.

硪扪都還晓 2024-12-31 19:36:12

数组确实具有多态行为——只有泛型类型没有。

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

你可以说:

Parcelable[] pa = new Uri[size];
Uri[] ua = (Uri[]) pa;

你不能说:

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

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

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

我只是想弄清楚为什么会这样。如果你想要一个解决方案,@solo 提供了一个不错的解决方案。

干杯

Arrays do have polymorphic behaviour - only generic types don't have.

That is, if Uri implements Parcelable then

you CAN say:

Parcelable[] pa = new Uri[size];
Uri[] ua = (Uri[]) pa;

you CANNOT say:

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

As you see we can cast pa back to Uri[]. Then what is the problem? This ClassCastException happens when your app is killed and later the saved array is recreated. When it is recreated the runtime does not know what kind of array (Uri[]) it was so it just creates a Parcelable[] and puts elements into it. Hence the ClassCastException when you try to cast it to Uri[].

Note that the exception does not happen (theoretically) when the process is not killed and the originally created array (Uri[]) is reused between state save/restore rounds. Like when you change the orientation.

I just wanted to make clear WHY it happened. If you want a solution @solo provided a decent one.

Cheers

倚栏听风 2024-12-31 19:36:12

我认为发生的事情如下:

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;

I think what's happening is something as follows:

class Parent { }

class MaleParent extends Parent { }

class FemaleParent extends Parent { }

If the scenario is something as above then the following will fail at runtime:

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

Something as follows does not raise the exception:

Parent[] parents = new MaleParent[]{};
MaleParent[] maleParents = (MaleParent[]) parents;
三人与歌 2024-12-31 19:36:12

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);
            }
        }
    }    
}

https://stackoverflow.com/a/8745966/72437 and https://stackoverflow.com/a/20073367/72437 have well explanation on why such crash happens.

https://stackoverflow.com/a/14866690/72437 also has a example on how we can workaround with this.

I would like to provide code examples, to help better understanding.

Let me demonstrate an example on why such incident fails sometimes.

An example to demonstrate why such crash happens

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);
            }
        }
    }    
}

An example to demonstrate on how we can fix this

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);
            }
        }
    }    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文