最近在看《SCJP指南》的时候,有一点理解不透,请大家先看如下的例子:public class InstanceOfDemo { public static void main(String[] args) {
System.out.println(new InstanceOfDemo() instanceof String); //compile time error
System.out.println(new InstanceOfDemo() instanceof Exception); //compile time error
System.out.println(new InstanceOfDemo() instanceof Object); //compilation and output true

System.out.println(new InstanceOfDemo() instanceof List); //compilation and output false
}
}我原本以为前两行会打印出false,但是竟然是编译错,上网查了一下中文资料,但是得到的最好的答案是:instanceof与Class的cast()方法相同。
我觉得这样仍然解释不通,从我的测试来看,我发现Java是不是对instanceof操作符进行了某种优化,也就是说:在编译器就对java.lang包的类进行了检查。
当然这只是我的猜测,希望大家能一起证明一下,太感谢了。

解决方案 »

  1.   

    你最后一个List应该在你类前面加上一条导入util包的语句 这样最后一个就会和前两个报同样的error了Java中lang包是默认导入的 
      

  2.   

    但是貌似对instanceof而言,只对lang包下的类进行了检查,也就是:
    对象 instanceof lang包下的类
    结果只会是编译错或者true?
      

  3.   

    楼主去看下面这个帖子吧,和你问的问题一模一样
    http://topic.csdn.net/t/20051208/14/4446224.html
      

  4.   

    谢谢啊,这个帖子我倒没有搜到,是很相似,但是我希望大家讨论的是:
    对instanceof而言,编译器检查的范围是不是仅限于java.lang,这是不是Java规范?
      

  5.   

    我是这么理解的 lang包里有什么 编译器是知道的 所以编译期知道你的这个类 不可能和String类,Exception有任何继承关系(不严格的表述啊  但不影响理解) 而Object肯定是没错的 一定是true的  但是编译期不知道List类是什么  所以编译期并没有马上判断该实例是否是List的实例 
      

  6.   

    我2#的例子很能说明问题了 你如果不去掉那个导入语句的话 编译器就能直接报错啊 关键是编译器不知道List是什么  你能指望它做什么呢?  所以编译器的检查范围不是仅仅局限在lang包里 不然你是不是觉得太局限了? 呵呵
      

  7.   

    你说的我还不是很懂,下面是全部的代码,你再看看:import java.io.IOException;
    import java.util.List;public class InstanceOfDemo { public static void main(String[] args) {
    System.out.println(new InstanceOfDemo() instanceof String); //compile time error
    System.out.println(new InstanceOfDemo() instanceof Exception); //compile time error
    System.out.println(new InstanceOfDemo() instanceof Object); //compilation and output true

    System.out.println(new InstanceOfDemo() instanceof List); //compilation and output false
    }
    }
      

  8.   

    我10#的表述有错误 应该说编译器判断一个实例是否是一个对象的对象的时候,首先需要知道这个对象是什么,如果你不导入那个util包的话,错误是“找不到符号”然后具体错误是“compilation and output false”。我想我现在明白了你问题的意思了  你是说 编译器同样知道lang包和util包,为啥对于String和Exception直接报编译错误 而对于Object和List却能运行 是吧?
      

  9.   

    instanceof可以自动向上转型所以Object 和 InstanceOfDemo 不会报错
    除此之外你给所有其他的对象编译器都会报错,不管是什么包下的
    但是楼主给的那个接口编译器没有报错,这个我也不懂了,也许是编译器不知道该对象的所有父类都实现了什么接口。
    我只能说,
    instanceof不存在楼主说的那个规则,只是instanceof一个接口的时候可以骗过编译器,但是对象是骗不过编译器的,不管什么包下的对象
     System.out.println(new InstanceofDemo() instanceof ArrayList);//compile time error
            System.out.println(new InstanceofDemo() instanceof List); //compilation and output false
            System.out.println(new InstanceofDemo() instanceof Runnable);//compilation and output false
            System.out.println(new InstanceofDemo() instanceof ActionListener);//compilation and output false
      

  10.   

    有什么问题啊,你想说什么?
    eclipse中是报:
    Incompatible conditional operand types InstanceOfDemo and String和Incompatible conditional operand types InstanceOfDemo and Exception。
      

  11.   


    怎莫会仅限于java.lang呢比如说
    自己写了两个类,类A继承类B
    那这个时候 
    new A() instanceof B
    你说这也会报错吗
    呵呵,肯定是不会的所以,范围应该是jvm找得到的类去匹配,也就是你classpath配的路径
    当然,如果在不同的包中,要先导入才是
      

  12.   


    类的类型是否匹配,在编译时就进行检查
    所以,instanceof前后的类如果不匹配的话,编译报错
    也就是说 instanceof前后的类 如果不存在继承关系,则编译报错
      

  13.   

    没有 那为什么List没有报编译错误呢 明显的 自定义类和List没有任何继承关系啊我现在有点同意这个优化一说了
      

  14.   


    哪有什么优化,List是接口,又不是类,所有的接口都不会报错。所有的类不管什么包下都报错。
    顺便改正一下我的错误,我上面的回复把类都写成了对象,不好意思
      

  15.   

    java解惑关于这方面的一段话:Type2.java:3: inconvertible types
    found : Type2, required: java.lang.String
    System.out.println(new Type2() instanceof String);
    ^
    该程序编译失败是因为instanceof 操作符有这样的要求:如果两个操作数的类
    型都是类,其中一个必须是另一个的子类型[JLS 15.20.2, 15.16, 5.5]。
    Type2
    和String 彼此都不是对方的子类型,所以instanceof 测试将导致编译期错误。
    这个错误有助于让你警惕instanceof 测试,它们可能并没有去做你希望它们做
    的事情。
      

  16.   

    恩 确实如你所说 接口都不报错 但是包会报错 没有lang包和不是lang包之分但是现在的问题是  为什么编译器要区分接口和类呢  难道extends和implement  一个是运行期的 一个是编译期的么?
      

  17.   

    14楼的朋友说的很清楚了
    呵呵,List是个接口所以,偶刚才说
    instanceof前后的类 如果不存在继承关系,则编译报错
    没错吧,呵呵也就是说
    类可以继承一个类
    但不可以说类继承接口,是实现接口
      

  18.   

    补充23#  或者是在编译instanceof的时候 编译期会去检查运算符两边是类 还是接口么  我比较倾向于这种观点
      

  19.   

    这么看 instanceof在编译的时候 运算符两端的两个元 会被编译期检查 如是是右端是接口 一律是编译没有问题的  如果两端是类 就会进行检查   这样就能保证不遗漏了  可以试试左边是接口 右边是类的情况 虽然这种情况理论上是不成立的 但是可以试试 呵呵 
      

  20.   

    都在看《JavaPuzzle》,~_~
    谁看完总结总结啊。
      

  21.   

    顺手贴一下JLS15.20.215.20.2 Type Comparison Operator instanceofThe type of a RelationalExpression operand of the instanceof operator must be a reference type or the null type; otherwise, a compile-time error occurs. The ReferenceType mentioned after the instanceof operator must denote a reference type; otherwise, a compile-time error occurs. It is a compile-time error if the ReferenceType mentioned after the instanceof operator does not denote a reifiable type (§4.7).
    At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException. Otherwise the result is false.If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error, then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.
    Consider the example program:class Point { int x, y; }
    class Element { int atomicNumber; }
    class Test {
            public static void main(String[] args) {
                    Point p = new Point();
                    Element e = new Element();
                    if (e instanceof Point) {       // compile-time error
                            System.out.println("I get your point!");
                            p = (Point)e;           // compile-time error
                    }
            }
    }
    This example results in two compile-time errors. The cast (Point)e is incorrect because no instance of Element or any of its possible subclasses (none are shown here) could possibly be an instance of any subclass of Point. The instanceof expression is incorrect for exactly the same reason. If, on the other hand, the class Point were a subclass of Element (an admittedly strange notion in this example):class Point extends Element { int x, y; }then the cast would be possible, though it would require a run-time check, and the instanceof expression would then be sensible and valid. The cast (Point)e would never raise an exception because it would not be executed if the value of e could not correctly be cast to type Point.
      

  22.   

    个人猜想,之所以接口的instanceof检查要在运行期进行是因为有动态代理机制的存在
      

  23.   

    理解instanceof关键还是需要注意一下泛型。
    对于一般的情形,比如
    可以看一下这个例子:import java.util.List;public class Test {    public static void main(String[] args) {
            //编译时无法确定getObject()返回的引用类型的具体类型,下面两句都能通过编译
            System.out.println(getObject() instanceof Object);
            System.out.println(getObject() instanceof String);        //编译时可以确定类型的,能够cast则编译通过,否则编译失败 
            Test test = new Test();
            System.out.println(test instanceof Test);//ok
            System.out.println(test instanceof Object); //ok
            //System.out.println(test instanceof String);//error! test is not a String        //跟泛型相关的注意一下
            //List是泛型类型,如果不指定泛型参数,成功编译
            System.out.println(test instanceof List);
            //如果不限定类型界限,通过编译
            System.out.println(test instanceof List<?>);        //指定泛型参数,编译时可确定类型,如果不能cast,编译不通过
            //System.out.println(test instanceof List<Test>);  //error!
        }    public static Object getObject() {
            return "Test";
        }
    }
      

  24.   

    学习啦!原来instanceof还有这样的限制!!
      

  25.   

    《SCJP指南》讲到,不能使用instanceof运算符跨越不同的类层次结构进行测试!也就是说,instanceof右操作数类必须在左侧引用所定义的一个继承、实现体系内。
      

  26.   

    关于Java里面instanceof的总结
      

  27.   

    if(a = 2)

    if(2 = 2)
    的编译区别
      

  28.   

    //System.out.println(test instanceof List<Test>);//error!
    请教,这一句怎么也编译通不过呢?
      

  29.   

    这一句中List <Test>的类型是确定的,而test显然不是这个类型,所以编译错误我说的List<?> ,List这些都需要运行的时候确定具体类型,编译时确定不了。
    所以编译通过,是否成功就看运行时了。
    建议读一下java语言规范。
      

  30.   

    又发现一个问题,希望大家再讨论一下(还不能结贴啊),测试代码如下:import java.util.HashMap;
    import java.util.List;public class Type1 { public static void main(String[] args) {
    System.out.println(null instanceof String); //compilation and output false

    String str = null;
    System.out.println(str instanceof List); //compile time error

    System.out.println(new HashMap() instanceof List); //compilation and output false
    }
    }这段代码是对《Java解惑》中谜题50的第一个例子的扩展,[color=#FF0000请注意第三行的编译错误,前面讨论的结果是:对于instanceof的第二个操作数,如果是接口,则不进行编译器检查[/color],那么这个例子是否推翻了这个结论呢?
      

  31.   

    不是好不好 instanceof 是在运行时进行类型检查的,主要是用于向下转型用
      

  32.   

    如果测试双方都是接口,则和1类似,没有明显的继承关系,则编译错误 ....
    我试过了,不会出编译错误啊!!!!!????????
            List l =null;
            System.out.println(l instanceof Exception);
      

  33.   

    试一下下面这段就知道了原因是出在一个类和一个接口上。如果是接口。则编译器在编译时无法确定其是否为其子类。但是如果是类。编译器可以检查其extends关键字对此处进行编译。interface Instance4t
    {

    }class Instance5t
    {

    }public class InstanceTest{ public static void main(String[] args)
    {
            System.out.println(new InstanceTest() instanceof String); //compile time error
            System.out.println(new InstanceTest() instanceof Instance4t); // FALSE
            System.out.println(new InstanceTest() instanceof Instance5t); //compile time error
            System.out.println(new InstanceTest() instanceof Object); //compilation and output true
            
            System.out.println(new InstanceTest() instanceof List); //compilation and output false
    }

    }