为什么抛出ClassCastException:char []无法强制转换为android.app.SharedPreferencesImpl

时间:2016-12-07 06:29:48

标签: java generics classcastexception

以下是例外日志:

java.lang.ClassCastException: char[] cannot be cast to android.app.SharedPreferencesImpl
at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:358)
at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:171)
at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:171)
at com.android.internal.telephony.cat.CatService.saveCmdToPreference(CatService.java:2632)
at com.android.internal.telephony.cat.CatService.handleDBHandler(CatService.java:2079)
at com.android.internal.telephony.cat.CatService.handleMessage(CatService.java:1841)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Loo|debug info:dalvik.system.VMStack.getThreadStackTrace(Native Method)|java.lang.Thread.getStackTrace(Thread.java:580)|java.lang.Thread.getAllStackTraces(Thread.java:522)|com.letv.bsp.crashhandler.utils.LogUtils.trace(LogUtils.java:86)|com.letv.bsp.crashhandler.CrashHandleService.reportException(CrashHandleService.java:915)|com.letv.bsp.crashhandler.CrashHandleService.onStartCommand(CrashHandleService.java:663)|android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3291)|android.app.ActivityThread.-wrap18(ActivityThread.java)|android.app.ActivityThread$H.handleMessage(ActivityThread.java:1674)|android.os.Handler.dispatchMessage(Handler.java:111)|android.os.Looper.loop(Looper.java:207)|android.app.ActivityThread.main(ActivityThread.java:5905)|java.lang.reflect.Method.invoke(Native Method)|com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)|com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)|, blk: false printBlacklist the current black list : 

以下是android.app.ContextImpl.getSharedPreferences的代码异常抛出

    @Override
public SharedPreferences getSharedPreferences(String name, int mode) {
    SharedPreferencesImpl sp;
    synchronized (ContextImpl.class) {
        if (sSharedPrefs == null) {
            sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
        }

        final String packageName = getPackageName();
        ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
        if (packagePrefs == null) {
            packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();
            sSharedPrefs.put(packageName, packagePrefs);
        }

        // At least one application in the world actually passes in a null
        // name.  This happened to work because when we generated the file name
        // we would stringify it to "null.xml".  Nice.
        if (mPackageInfo.getApplicationInfo().targetSdkVersion <
                Build.VERSION_CODES.KITKAT) {
            if (name == null) {
                name = "null";
            } // here is the line 358
        }

        sp = packagePrefs.get(name);
        if (sp == null) {
            File prefsFile = getSharedPrefsFile(name);
            sp = new SharedPreferencesImpl(prefsFile, mode);
            packagePrefs.put(name, sp);
            return sp;
        }
    }
    if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
        getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
        // If somebody else (some other process) changed the prefs
        // file behind our back, we reload it.  This has been the
        // historical (if undocumented) behavior.
        sp.startReloadIfChangedUnexpectedly();
    }
    return sp;
}

让我们假设日志信息是正确的,它几乎应该是正确的。

我的第一个问题是:在ContextImpl.java文件的第358行抛出异常是什么意思?那里只有右支撑。

我想第358行下面的语句是异常

的根本情况
sp = packagePrefs.get(name);

因为sp声明为SharedPreferencesImpl,并且当get方法返回并赋值时它应该有一个强制转换操作,如果返回的值是char [],那么抛出异常应抛出,这个解释非常合理。但是,在

声明后,packagePrefs中的值已参数化为SharedPreferencesImpl
packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();

因此,它应该没有机会将char []的值类型放入packagePrefs中。然后,我再次感到困惑,代码出现在这个例外的原因和原因。

还有另一个类似的问题,日志是:

    java.lang.ClassCastException: char[] cannot be cast to              com.android.internal.util.StateMachine$LogRec
at com.android.internal.util.StateMachine$LogRecords.add(StateMachine.java:665)
at com.android.internal.util.StateMachine$SmHandler.performTransitions(StateMachine.java:830)
at com.android.internal.util.StateMachine$SmHandler.handleMessage(StateMachine.java:801)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.os.HandlerThread.run(HandlerThread.java:61)

相应的代码位于com.android.internal.util.StateMachine.LogRecords:

        private Vector<LogRec> mLogRecVector = new Vector<LogRec>();
        synchronized void add(StateMachine sm, Message msg, String messageInfo, IState state,
            IState orgState, IState transToState) {
        mCount += 1;
        if (mLogRecVector.size() < mMaxSize) {
            mLogRecVector.add(new LogRec(sm, msg, messageInfo, state, orgState, transToState));
        } else {
            LogRec pmi = mLogRecVector.get(mOldestIndex);
            mOldestIndex += 1;
            if (mOldestIndex >= mMaxSize) {
                mOldestIndex = 0;
            }
            pmi.update(sm, msg, messageInfo, state, orgState, transToState);
        }
    }

它似乎都是关于泛型的问题。希望来自专家的帮助,并提前感谢。

1 个答案:

答案 0 :(得分:0)

对于第一个问题(行号与错误不对应),我猜你自上次编译后添加了三行(可能是name = "null"条件)。任何时候你看到似乎没有排队的堆栈跟踪强烈暗示你的源和二进制文件不同步。

对于第二个问题,我们不应该看到ClassCastException,因为packagePrefsmLogRecVector是通用的,我认为如果您的代码片段编译(这可能会运行),这似乎是不可能的如果sSharedPrefs是原始类型,则会出现问题,但我认为情况并非如此)。我的第一个理论是你需要重新构建(关于堆栈跟踪与源代码不对应的暗示)。

如果完全重建不起作用,我必须假设这是一个特定于Android的问题(也许你正在使用ProGuard?)。你能在OracleJDK或OpenJDK中复制这个吗?如果你可以创建MCVE我们可以用它复制问题,那将有助于深入了解。