在调用 instanceof 之前是否需要进行 null 检查?

Is null check needed before calling instanceof?

提问人:Johan Lübcke 提问时间:6/1/2010 最后编辑:jscsJohan Lübcke 更新时间:8/4/2022 访问量:340123

问:

会返回或抛出一个?null instanceof SomeClassfalseNullPointerException

java nullpointerException null

评论

1赞 8/15/2013
对于任何 Compare 或 Equals 或类似方法,它也是“重要”的,或者至少非常有用,或者至少非常有用,这些方法旨在仅在相同类型的非 null 对象上成功,并保护您免受单行中的“愚蠢情况”的影响。更少的代码 = 更少的错误。
20赞 Scott Mermelstein 8/27/2013
为了权衡“这有用吗?”的争论 - 我从来没有编写过自己的 Java 代码(所以不容易知道规范在哪里,编译测试将非常不平凡),但我目前正在手动将 Java 转换为 JavaScript。我的代码在空引用上失败,谷歌搜索让我看到了接受的答案,这证实了这是预期的行为,并且我缺少隐式空检查。就我而言,非常有用。
0赞 chaotic3quilibrium 2/10/2023
我利用了检查来实现一个非常紧密的 Java 实现,它比我看到的由 Eclipse 和 IntelliJ 自动生成的那些更清晰:stackoverflow.com/a/75402885/501113instanceofnullequals()

答:

319赞 Bozho 6/1/2010 #1

使用 null 引用作为第一个操作数返回 。instanceoffalse

评论

295赞 PL_kolek 9/23/2015
(现在在谷歌上找到这个问题需要 10 秒钟)
0赞 MrYellow 11/3/2022
当用作第一个操作数时,也返回 .乐趣!!nullinstanceoffalse
0赞 maraca 1/10/2023
@MrYellow这将是语法错误,则需要使用括号。
0赞 MrYellow 1/12/2023
这是有效的语法,只是令人困惑。 是真的。!null
1赞 Valerio Bozz 3/10/2023
@MrYellow 请注意,这个问题是关于 Java 的,而不是 JavaScript 或其他具有“真实”等概念的语言
28赞 RoflcoptrException 6/1/2010 #2

不,不是。 如果它的第一个操作数是 ,则返回。instanceoffalsenull

2174赞 Andy Thomas 6/1/2010 #3

不,在使用 instanceof 之前不需要进行 null 检查。

表达式为 if is 。x instanceof SomeClassfalsexnull

Java 11 语言规范在第 15.20.2 节 “类型比较运算符 instanceof” 中简明扼要地表达了这一点。(Java 17 在引入 instanceof patternmatching 之后,就不那么简洁地表达了这一点。

“在运行时,运算符的结果是,如果 RelationalExpression 的值为 不为 null,引用可以是 强制转换为 ReferenceType,而不引发 . 否则结果是。instanceoftrueClassCastExceptionfalse

因此,如果操作数为 null,则结果为 false。

评论

441赞 Luke 1/9/2013
这个答案比因为当前行为与保证行为不同更正确。try it
4赞 Kevin Meredith 11/21/2013
这个问题在约书亚·布洛赫(Joshua Bloch)关于对象平等的章节中发挥作用 - amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683Effective Java
22赞 Andy Thomas 11/21/2013
具体来说,在第 8 项中,他指出,在 equals() 方法中,一个 instanceof 运算符有两个用途——它验证参数是否为非 null 且类型正确。"...因此,您不需要单独的 null 检查。
5赞 Andy Thomas 8/3/2015
@BenThurley - 过去和现在的 Java 规范保证了该行为。我认为卢克的观点解决了实验在确定当下有保证的行为方面的局限性。
4赞 Holger 1/23/2020
@GabrielBB这就像用红笔在红纸上写字一样。即使它没有意义,由于普遍有可能将任意笔与任意纸组合在一起,这是可能的。在笔上实施“相同颜色的书写”检查会使技术复杂化,几乎没有好处。
85赞 Jin Kwon 7/29/2013 #4

确实是非常好的问题。我只是自己试过。

public class IsInstanceOfTest {

    public static void main(final String[] args) {

        String s;

        s = "";

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));

        s = null;

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));
    }
}

指纹

true
true
false
false

JLS / 15.20.2。类型比较运算符 instanceof

在运行时,运算符的结果是,如果 RelationalExpression 的值不是,则可以将引用强制转换为 ReferenceType,而不会引发 .否则,结果是 。instanceoftruenullClassCastExceptionfalse

API / 类#isInstance(Object)

如果此对象表示接口,则此方法返回指定参数的类或任何超类是否实现此接口;否则返回。如果此对象表示基元类型,则此方法返回 。ClasstrueObjectfalseClassfalse

评论

1赞 Kai Wang 9/11/2017
有点令人困惑。s 是一个 String,因为它说 “String s”,s 不是 String,因为它是 null。那么s到底是什么?
1赞 Jin Kwon 9/12/2017
@KaiWang只是一个对象引用变量。它可以引用实际存在的 object(),也可以引用 (the) 字面引用。s""null
0赞 Kai Wang 9/12/2017
我仍然很困惑。s 现在可能为 null,但以后只能指向 String 实例。它不能像 Integer 那样指向。所以它仍然是一个字符串,即使它是一个 null。只是没有多大意义......
1赞 Matthew Read 10/6/2017
@KaiWang 您将变量类型与实际对象的类型混淆了。变量不是实例;它们实际上只是指针。 不是字符串数据,无论指向哪个变量。 例如,与 不同。nulls instanceof Stringfield.getType().equals(String.class)
3赞 Timo Türschmann 2/2/2018
@KaiWang你必须想象在调用中,被替换为实际值,因此这将变成 和 。这样想可能更有意义。s instanceof Strings"" instanceof Stringnull instanceof String
2赞 Nikhil Kumar 4/1/2015 #5

运算符不需要显式检查,因为如果操作数为 ,则它不会抛出 。instanceofnullNullPointerExceptionnull

在运行时,如果关系表达式的值不是,则运算符的结果为 true,并且可以将引用强制转换为引用类型,而不会引发类强制转换异常。instanceofnull

如果操作数为 ,则运算符返回,因此不需要显式 null 检查。nullinstanceoffalse

请看下面的例子,

public static void main(String[] args) {
         if(lista != null && lista instanceof ArrayList) {                     //Violation
                System.out.println("In if block");
         }
         else {
                System.out.println("In else block");
         }
}

的正确用法如下图所示,instanceof

public static void main(String[] args) {
      
         if(lista instanceof ArrayList){                     //Correct way
                  System.out.println("In if block");
         }
            else {
                 System.out.println("In else block");
         }  
}
25赞 Attila Tanyi 3/22/2018 #6

就像一个花絮

甚至 ((A)null) 将返回 。(instanceof A)false


(如果类型转换看起来令人惊讶,有时你必须这样做,例如在这样的情况下:null

public class Test
{
  public static void test(A a)
  {
    System.out.println("a instanceof A: " + (a instanceof A));
  }

  public static void test(B b) {
    // Overloaded version. Would cause reference ambiguity (compile error)
    // if Test.test(null) was called without casting.
    // So you need to call Test.test((A)null) or Test.test((B)null).
  }
}

所以会打印。Test.test((A)null)a instanceof A: false


P.S.:如果你正在招聘,请不要把这个作为面试问题。:D

评论

7赞 alife 12/31/2021
关于你的PS:如果有人真的在面试中提出一些问题,那么他们太年轻了,不适合面试。在面试中,任何问题的正确或错误答案都无关紧要。重要的是围绕这个话题的后续对话
3赞 Marinos An 4/7/2021 #7
  • 在 instanceof 之前不需要 null 检查
  • 在验证为 true 的 instanceof 之后,不需要 null 检查

以下是 null 安全的:

if(couldbenull instanceof Comparable comp){
   return comp.compareTo(somethingElse);
}
//java < 14
if(couldbenull instanceof Comparable){
   return ((Comparable)couldbenull).compareTo(somethingElse);
}
6赞 TriS 1/26/2022 #8

不,在调用 之前不需要检查。如果其值为 ,则始终返回 false。nullinstanceofnull

根据 Java 语言规范,使用 .instanceof

在运行时,如果 RelationalExpression 的值不为 null,引用可以 转换为 ReferenceType,而不引发 ClassCastException。 否则结果为 false

因此,我们可以推断 java 也有一种叫做类型的东西,并且这个 null 类型在运算符中被检查,这显然返回 false,因为它需要一个特定的类型。nullinstanceof

Java 编程语言中有两种类型:原始类型和引用类型。 根据 Java 类型和值规范

还有一个特殊的 null 类型,表达式 null 的类型, 它没有名字。因为 null 类型没有名称,所以不可能 声明 null 类型的变量或强制转换为 null 类型。 null 引用是 null 表达式的唯一可能值 类型。空参照始终可以进行加宽参照 转换为任何引用类型。

从 Java 14 开始,尤其是在 LTS Java 17 中,我们有一个增强的 .我们有模式匹配功能,可以在类型比较后执行强制转换。instanceof

public static void main(String[] args) {
    Object testObject = "I am a string";
    List<Object> testList = null;
    if (testList instanceof List) {
        System.out.println("instance of list");
    } else {
        System.out.println("null type");
    }
    //Enhanced instanceof with type conversion - tested with JDK 17
    if (testObject instanceof String str) {
        System.out.println(str.toUpperCase());
    }
}

输出

null type
I AM A STRING