有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

安卓取消引用可能会产生“java”。lang.NullPointerException'

以下代码段在Android Studio中生成一个lint警告

    Bundle extras = getIntent().getExtras();
    if (extras != null && extras.getString(REDIRECT_KEY) != null) {
        switch (extras.getString(REDIRECT_KEY)) { ... 

extras.getString(REDIRECT_KEY)产生警告

enter image description here

Dereference of 'extras.getString(REDIRECT_KEY)' may produce 'java.lang.NullPointerException'

但我看不出会发生这种情况。这是不是lint检查中的一个bug,它以前根本不识别if中的null检查?还是我错过了什么

编辑: 将代码更改为以下,是否删除了警告

if(getIntent() != null && getIntent().getStringExtra(REDIRECT_KEY) != null){
        switch (getIntent().getStringExtra(REDIRECT_KEY)){
            ...
        }
    }

但这只是因为这样,这种皮棉检查工作(至少我猜)。如果我在这张支票上显示更多信息,它会在某一点上显示

Variables, method parameters and return values marked as @Nullable or @NotNull are treated as nullable (or not-null, respectively) and used during the analysis to check nullability contracts

查看Bundle和Intent的源代码显示:

/**
 * Retrieve extended data from the intent.
 *
 * @param name The name of the desired item.
 *
 * @return the value of an item that previously added with putExtra()
 * or null if no String value was found.
 *
 * @see #putExtra(String, String)
 */
public String getStringExtra(String name) {
    return mExtras == null ? null : mExtras.getString(name);
}

和基束

/**
 * Returns the value associated with the given key, or null if
 * no mapping of the desired type exists for the given key or a null
 * value is explicitly associated with the key.
 *
 * @param key a String, or null
 * @return a String value, or null
 */
@Nullable
public String getString(@Nullable String key) {
    unparcel();
    final Object o = mMap.get(key);
    try {
        return (String) o;
    } catch (ClassCastException e) {
        typeWarning(key, o, "String", e);
        return null;
    }
}

如您所见,BaseBundle将其返回值设置为@Nullable,而Intent则不设置。因此,使用getStringExtra只会删除符号,而不会删除原因。我仍然猜测这是由于不充分的皮棉检查造成的,而不是我这边的错误编码。或者还有人看到可以抛出空指针的场景吗


共 (1) 个答案

  1. # 1 楼答案

    看看这个取自here的例子

    class Argument {
    
        public final static int TOMAYTO = 0;
        public final static int TOMAHTO = 1;
    
        static void argue() {
    
            int say = TOMAYTO;
    
            while (true) {
    
                switch (say) {
    
                case TOMAYTO:
    
                    say = TOMAHTO;
                    break;
    
                case TOMAHTO:
    
                    say = TOMAYTO;
                    break;
                }
            }
        }
    }
    

    javac为argue()方法生成的字节码如下所示:

       0 iconst_0 // Push constant 0 (TOMAYTO)
       1 istore_0 // Pop into local var 0: int say = TOMAYTO;
       2 iload_0 // Push key for switch from local var 0
                              // Perform switch statement: switch (say) {...
                              // Low case value is 0, high case value is 1
                              // Default branch offset will goto 2
       3 tableswitch 0 to 1: default=2
                0: 24 // case 0 (TOMAYTO): goto 24
                1: 29 // case 1 (TOMAHTO): goto 29
    
                              // Note that the next instruction starts at address 24,
                              // which means that the tableswitch took up 21 bytes
      24 iconst_1 // Push constant 1 (TOMAHTO)
      25 istore_0 // Pop into local var 0: say = TOMAHTO
      26 goto 2 // Branch unconditionally to 2, top of while loop
      29 iconst_0 // Push constant 1 (TOMAYTO)
      30 istore_0 // Pop into local var 0: say = TOMAYTO
      31 goto 2 // Branch unconditionally to 2, top of while loop
    

    正如您可以看到的,对于具有字符串数据类型的switch语句,表开关已经完成,对于每种情况,传递给switch的值都会与该情况的值进行比较,因此这意味着在您的情况下,可以多次调用extras.getString,而无需调用之前的if检查,因此,由于extras是一个bundle,所以它有可能被取消引用,并导致空指针异常

    创建一个局部变量而不是多次调用该方法一直是一个很好的做法,您可以看看this presentation by Jake Wharton来了解原因