【问题标题】:What is the 'instanceof' operator used for in Java?Java 中的“instanceof”运算符是做什么用的?
【发布时间】:2011-11-10 22:19:19
【问题描述】:

instanceof 运算符的用途是什么?我见过类似的东西

if (source instanceof Button) {
    //...
} else {
    //...
}

但这对我来说毫无意义。我已经完成了我的研究,但只提出了示例,没有任何解释。

【问题讨论】:

  • 在这里提问并没有错,但是如果你正在学习 Java,你可能想要一本书。任何体面的 Java 书籍都会有这个问题的答案,以及接下来的 1000 本书。
  • 这样的算子有很多特定的用途。如果它要求您解释其中一个对您来说没有意义的示例,这将是一个具体的问题。
  • 下面的答案是正确的,但是请注意,instanceof 是一个过度使用的运算符,十分之九,它可以被正确使用多态性所取代(不总是,但经常)
  • 我会比 Richard 更进一步:我从未见过 instanceof 的有效用法。它仅对在设计不佳的代码之上的快速破解有用。如果您不喜欢 OOP,请用另一种语言编写(有很多)。对 instanceof 说“不”!
  • @ScottBiggs 在覆盖equals 时,是否有一个很好的替代instanceof 的方法?

标签: java instanceof


【解决方案1】:

如果sourceobject 变量,instanceof 是一种检查它是否为Button 的方法。

【讨论】:

    【解决方案2】:

    这是一个运算符,如果表达式的左侧是 右侧类名的实例,则返回 true。

    这样想。假设您所在街区的所有房屋都是根据相同的蓝图建造的。十间房屋(物件),一套蓝图(类定义)。

    instanceof 在您拥有一组对象但不确定它们是什么时是一个有用的工具。假设您在表单上有一组控件。您想读取任何复选框的选中状态,但您不能询问普通旧对象的选中状态。相反,您会查看每个对象是否是一个复选框,如果是,请将其转换为一个复选框并检查其属性。

    if (obj instanceof Checkbox)
    {
        Checkbox cb = (Checkbox)obj;
        boolean state = cb.getState();
    }
    

    【讨论】:

    • 也就是说,使用instanceof可以让downcast安全。
    【解决方案3】:

    this site所述:

    instanceof 运算符可用于测试对象是否属于 具体类型...

    if (objectReference instanceof type)
    

    一个简单的例子:

    String s = "Hello World!"
    return s instanceof String;
    //result --> true
    

    但是,将instanceof 应用于空引用变量/表达式 返回 false。

    String s = null;
    return s instanceof String;
    //result --> false
    

    由于子类是其超类的“类型”,您可以使用 instanceof 来验证这个...

    class Parent {
        public Parent() {}
    }
    
    class Child extends Parent {
        public Child() {
            super();
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Child child = new Child();
            System.out.println( child instanceof Parent );
        }
    }
    //result --> true
    

    我希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      instanceof 关键字是一个二元运算符,用于测试对象(实例)是否是给定类型的子类型。

      想象一下:

      interface Domestic {}
      class Animal {}
      class Dog extends Animal implements Domestic {}
      class Cat extends Animal implements Domestic {}
      

      想象一个dog对象,用Object dog = new Dog()创建,然后:

      dog instanceof Domestic // true - Dog implements Domestic
      dog instanceof Animal   // true - Dog extends Animal
      dog instanceof Dog      // true - Dog is Dog
      dog instanceof Object   // true - Object is the parent type of all objects
      

      但是,对于Object animal = new Animal();

      animal instanceof Dog // false
      

      因为AnimalDog 的超类型并且可能不那么“精致”。

      还有,

      dog instanceof Cat // does not even compile!
      

      这是因为Dog 既不是Cat 的子类型也不是超类型,而且它也没有实现它。

      请注意,上面用于dog 的变量是Object 类型。这是为了表明instanceof 是一个运行时操作,并将我们带到一个/用例:在运行时根据对象类型做出不同的反应。

      注意事项:expressionThatIsNull instanceof T 对于所有类型 T 都是 false。

      【讨论】:

      • 我刚试过 - Object dog = new Dog(); System.out.println(dog instanceof Cat);。这编译得很好并打印false。不允许编译器在编译时确定 dog 不能是 Cat(根据 JLS 中的规则)
      • @ErwinBolwidt 你在尝试时犯了一个错误。对于任何想知道的人:JLS 第 15.20.2 节是您正在寻找的那个。对于一个最小的非工作示例:boolean b = "foo" instanceof Integer;
      • @FelixS 您需要再次阅读答案。答案是关于Object indirect = ...; if (indirect instanceof Something)。这与您似乎假设的 if (literal instanceof Something) 无关。
      • @ErwinBolwidt 哦,对了,我一定跳过了Object dog 部分。我的错!
      • dog instanceof Cat // does not even compile!(因为它是一个类)。如果Cat 是一个接口,那么它将编译。
      【解决方案5】:

      非常简单的代码示例:

      If (object1 instanceof Class1) {
         // do something
      } else if (object1 instanceof Class2) {
         // do something different
      }
      

      这里要小心。在上面的示例中,如果 Class1 是 Object,则第一个比较将始终为真。所以,就像例外一样,等级顺序很重要!

      【讨论】:

        【解决方案6】:

        instanceof 运算符将对象与指定类型进行比较。您可以使用它来测试对象是类的实例、子类的实例还是实现特定接口的类的实例。

        http://download.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

        【讨论】:

          【解决方案7】:

          正如其他答案中提到的,instanceof 的典型典型用法是检查标识符是否指的是更具体的类型。示例:

          Object someobject = ... some code which gets something that might be a button ...
          if (someobject instanceof Button) {
              // then if someobject is in fact a button this block gets executed
          } else {
              // otherwise execute this block
          }
          

          但是请注意,左侧表达式的类型必须是右侧表达式的父类型(请参阅JLS 15.20.2Java Puzzlers, #50, pp114)。例如,以下将无法编译:

          public class Test {
              public static void main(String [] args) {
                  System.out.println(new Test() instanceof String); // will fail to compile
              }
          }
          

          编译失败并显示消息:

          Test.java:6: error: inconvertible types
                  System.out.println(t instanceof String);
                                 ^
            required: String
            found:    Test
          1 error
          

          因为Test 不是String 的父类。 OTOH,这可以完美编译并按预期打印false

          public class Test {
              public static void main(String [] args) {
                  Object t = new Test();
                  // compiles fine since Object is a parent class to String
                  System.out.println(t instanceof String); 
              }
          }
          

          【讨论】:

          • 感谢您链接到规范!
          【解决方案8】:

          此运算符允许您确定对象的类型。 它返回一个boolean 值。

          例如

          package test;
          
          import java.util.Date;
          import java.util.Map;
          import java.util.HashMap;
          
          public class instanceoftest
          {
              public static void main(String args[])
              {
                  Map m=new HashMap();
                  System.out.println("Returns a boolean value "+(m instanceof Map));
                  System.out.println("Returns a boolean value "+(m instanceof HashMap));
                  System.out.println("Returns a boolean value "+(m instanceof Object));
                  System.out.println("Returns a boolean value "+(m instanceof Date));
              }
          } 
          

          输出是:

          Returns a boolean value true
          Returns a boolean value true
          Returns a boolean value true
          Returns a boolean value false
          

          【讨论】:

            【解决方案9】:
            public class Animal{ float age; }
            
            public class Lion extends Animal { int claws;}
            
            public class Jungle {
                public static void main(String args[]) {
            
                    Animal animal = new Animal(); 
                    Animal animal2 = new Lion(); 
                    Lion lion = new Lion(); 
                    Animal animal3 = new Animal(); 
                    Lion lion2 = new Animal();   //won't compile (can't reference super class object with sub class reference variable) 
            
                    if(animal instanceof Lion)  //false
            
                    if(animal2 instanceof Lion)  //true
            
                    if(lion insanceof Lion) //true
            
                    if(animal3 instanceof Animal) //true 
            
                }
            }
            

            【讨论】:

              【解决方案10】:

              您可以使用 Map 对实例进行更高的抽象

              private final Map<Class, Consumer<String>> actions = new HashMap<>();
              

              然后让这样的地图添加一些动作:

              actions.put(String.class, new Consumer<String>() {
                      @Override
                      public void accept(String s) {
                         System.out.println("action for String");       
                      }
                  };
              

              然后拥有一个未知类型的对象,您可以从该地图中获得特定的操作:

              actions.get(someObject).accept(someObject)
              

              【讨论】:

                【解决方案11】:

                关键字实例在您想知道特定对象的实例时很有帮助。

                假设你抛出异常,当你有 catch 时,执行 sum 自定义操作,然后再次按照你的逻辑继续(抛出或日志等)

                示例: 1) 用户创建自定义异常“InvalidExtensionsException”并按逻辑抛出

                2) 现在在 catch 块中 捕获(异常 e){ 如果异常类型为“InvalidExtensionsException”,则执行求和逻辑

                InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;
                

                3) 如果您不检查实例且异常类型为 Null 指针异常,您的代码将中断。

                所以你的逻辑应该在实例内部 if (e instanceof InvalidExtensionsException){ InvalidExtensionsException InvalidException =(InvalidExtensionsException)e; }

                上面的例子是错误的编码习惯但是这个例子是帮助你理解它的实例的使用。

                【讨论】:

                  【解决方案12】:

                  可用作相等性检查的简写。

                  所以这段代码

                  if(ob != null && this.getClass() == ob.getClass) {
                  }
                  

                  可以写成

                  if(ob instanceOf ClassA) {
                  }
                   
                  

                  【讨论】:

                    【解决方案13】:

                    instanceof 运算符用于检查对象是否为指定类型的实例。 (类或子类或接口)。

                    instanceof 也称为类型比较运算符,因为它将实例与类型进行比较。它返回真或假。

                    class Simple1 {  
                    public static void main(String args[]) {  
                    Simple1 s=new Simple1();  
                    System.out.println(s instanceof Simple1); //true  
                    }  
                    }  
                    

                    如果我们将 instanceof 运算符应用于任何具有 null 值的变量,它会返回 false。

                    【讨论】:

                      【解决方案14】:
                      class Test48{
                      public static void main (String args[]){
                      Object Obj=new Hello();
                      //Hello obj=new Hello;
                      System.out.println(Obj instanceof String);
                      System.out.println(Obj instanceof Hello);
                      System.out.println(Obj instanceof Object);
                      Hello h=null;
                      System.out.println(h instanceof Hello);
                      System.out.println(h instanceof Object);
                      }
                      }  
                      

                      【讨论】:

                      • 不要在 StackOverflow 上仅发布代码答案。请继续添加解释。
                      【解决方案15】:

                      大多数人都正确解释了这个问题的“什么”,但没有人正确解释“如何”。

                      所以这里有一个简单的说明:

                      String s = new String("Hello");
                      if (s instanceof String) System.out.println("s is instance of String"); // True
                      if (s instanceof Object) System.out.println("s is instance of Object"); // True
                      //if (s instanceof StringBuffer) System.out.println("s is instance of StringBuffer"); // Compile error
                      Object o = (Object)s;
                      if (o instanceof StringBuffer) System.out.println("o is instance of StringBuffer"); //No error, returns False
                      else System.out.println("Not an instance of StringBuffer"); // 
                      if (o instanceof String) System.out.println("o is instance of String"); //True
                      

                      输出:

                      s is instance of String
                      s is instance of Object
                      Not an instance of StringBuffer
                      o is instance of String
                      

                      s 与 StringBuffer 比较时出现编译器错误的原因在 docs 中有很好的解释:

                      您可以使用它来测试对象是类的实例、子类的实例还是实现特定接口的类的实例。

                      这意味着 LHS 必须是 RHS 的实例或实现 RHS 或扩展 RHS 的类的实例。

                      那么如何使用instanceof呢?
                      由于每个类都扩展了对象,因此将 LHS 类型转换为对象将始终对您有利:

                      String s = new String("Hello");
                      if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //No compiler error now :)
                      else System.out.println("Not an instance of StringBuffer");
                      

                      输出:

                      Not an instance of StringBuffer
                      

                      【讨论】:

                      • 在最后一个例子中,为什么它返回“不是 StringBuffer 的实例”?由于您在 LHS 上将 s 类型转换为 Object 并检查它是否是 RHS 的实例,if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be true,因为我们正在将 s 类型转换为 Object?
                      • 因为 s 是对 String 对象的引用(Java 采用不同于 C++ 的动态多态性)并且 String 不是 StringBuffer 的子类。
                      【解决方案16】:

                      最好的解释是jls。 始终尝试检查消息来源所说的内容。在那里你会得到最好的答案以及更多。 在这里复制一些部分:

                      instanceof 的 RelationalExpression 操作数的类型 运算符必须是引用类型或空类型;否则,一个 发生编译时错误。

                      如果后面提到的 ReferenceType 是编译时错误 instanceof 运算符不表示可具体化的引用类型 (§4.7)。

                      如果将 RelationalExpression 强制转换为 ReferenceType(第 15.16 节) 将作为编译时错误被拒绝,然后 instanceof 关系表达式同样会产生编译时错误。在这样的 一种情况,instanceof 表达式的结果永远不会是 真的。

                      【讨论】:

                        【解决方案17】:

                        javainstanceof运算符用于测试对象是否为指定类型(类或子类或接口)的实例。

                        java 中的 instanceof 也称为类型comparison operator,因为它将实例与类型进行比较。它返回truefalse。如果我们将instanceof 运算符应用于任何具有null 值的变量,它将返回false

                        从包含 JEP 305 的 JDK 14+ 开始,我们还可以为 instanceof 进行“模式匹配”

                        模式基本上测试一个值是否具有某种类型,并且当它具有匹配类型时可以从该值中提取信息。 模式匹配可以更清晰、更有效地表达系统中的通用逻辑,即从对象中有条件地移除组件。

                        在 Java 14 之前

                        if (obj instanceof String) {
                            String str = (String) obj; // need to declare and cast again the object
                            .. str.contains(..) ..
                        }else{
                             str = ....
                        }
                        

                        Java 14 增强功能

                        if (!(obj instanceof String str)) {
                            .. str.contains(..) .. // no need to declare str object again with casting
                        } else {
                            .. str....
                        }
                        

                        我们也可以把类型检查和其他条件结合起来

                        if (obj instanceof String str && str.length() > 4) {.. str.contains(..) ..}
                        

                        instanceof 中使用模式匹配应该会减少 Java 程序中显式转换的总数。

                        PSinstanceOf 只会在对象不为空时匹配,然后才可以赋值给str

                        【讨论】:

                          【解决方案18】:

                          instanceof 运算符也可以在运行时对象(listObj)中存在的元素类型未知时使用。在这些情况下,可以使用 instanceof 运算符来确定元素类型,并有助于根据需求进行进一步处理。

                          例如:

                             String str = "";
                             int a = 0;
                             Integer b = null;
                          
                              List listObj = new ArrayList<>();
                              listObj.add("String");
                              listObj.add(100);
                              listObj.add(10.5);
                              listObj.add(1l);
                              
                              if (listObj.get(0) instanceof String) {
                                  System.out.println("String");
                                  str = (String)listObj.get(0);
                              }
                              
                              if (listObj.get(1) instanceof Integer) {
                                  System.out.println("Integer");
                                   a = (int)listObj.get(1);
                                   b = (Integer)listObj.get(1);
                              }
                              
                              if (listObj.get(2) instanceof Double) {
                                  System.out.println("Double");
                              }
                              
                              if (listObj.get(3) instanceof Long) {
                                  System.out.println("Long");
                              }
                          

                          如果从对象中检索的值分配给变量,JVM 会在编译时要求您将其转换为特定类型。

                          让我们考虑一下:

                          int x = (String)listObj.get(0); 
                          

                          // 在上面的例子中,从 listObj 中检索的元素是 String 并且被强制转换为 int。这将解决编译时错误。但是在执行时JVM会抛出ClassCastException。

                          因此,我们可以使用instanceof运算符检查并将值分配给正确的变量以避免错误,而不是随机分配值给不匹配类型的变量。

                          【讨论】:

                            猜你喜欢
                            • 2011-01-27
                            • 2020-02-07
                            • 2014-09-16
                            • 2013-08-08
                            • 2012-07-29
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2014-11-18
                            相关资源
                            最近更新 更多