问:下面程序有什么问题吗?运行结果是什么?
"demo" instanceof Object; //1,true
new String() instanceof String; //2,true
new Object() instanceof String; //3,false
'A' instanceof Character; //4,编译报错
null instanceof String; //5, false
(String) null instanceof String; //6,false
new Date() instanceof String; //7,false
class GenericClass<T> {
public boolean isDateInstance(T t) {
return t instanceof Date;
}
}
new GenericClass<String>().isDateInstance(""); //8,false
"demo" instanceof null; //9,编译错误
class B {
}
class A {
}
new B() instanceof A; //10,编译错误
String str[] = new String[2];
str instanceof String[]; //11,true
答:答案如题目后面注释所示,解释如下描述。
注释 1 的返回值是 true,"demo" 是一个字符串,字符串继承自 Object,所以返回 true。
注释 2 的返回值是 true,因为一个类的对象当然是它的实例了。
注释 3 的返回值是 false,因为 Object 是父类,其对象当然不是 String 类的实例了,要注意的是这句话是可以编译通过的,只要 instanceof 关键字的左右两个操作数有继承或实现关系就可以编译通过。
注释 4 编译不通过,因为 'A' 是一个 char 类型,也就是一个基本类型,不是一个对象,instanceof 只能用于对象的判断,不能用于基本类型的判断。
注释 5 返回值是 false,因为这是 instanceof 特有的规则,若左操作数是 null 则结果直接返回 false,不再运算右操作数是什么类,这和我们经常用到的 equals、toString 方法不同。
注释 6 返回值是 false,因为 null 没有类型,所以即使做类型转换还是 null。
注释 7 编译通不过,因为 Date 类和 String 没有继承或实现关系,所以在编译时直接就报错了,instanceof 操作符的左右操作数必须有继承或实现关系,否则编译会失败。
注释 8 返回值是 false,因为虽然 T 是 String 类型且与 Date 之间没有继承或实现关系,但是 Java 泛型在编译成字节码时 T 已经被换成了 Object 类型了(泛型擦除),传递的实参是 String 类型而已。
注释 9 编译不通过,instanceof 的右操作符必须是一个接口或者类,null 啥都不是,所以咯。
注释 10 编译通不过,因为 Date 类和 String 没有继承或实现关系,所以在编译时直接就报错了,instanceof 操作符的左右操作数必须有继承或实现关系,否则编译会失败。
注释 11 返回值为 true,因为数组类型也可以使用 instanceof 来判断。
问:说说 java 的 instanceof 与 obj.instanceof(class) 的区别?
答:java 中的 instanceof 运算符用来在运行时指出对象是否是特定类的一个实例,通过返回一个布尔值来指出这个对象是否是这个特定类或者是它的子类的一个实例;用法为 result = object instanceof class
,参数 result 布尔类型,object 为必选项的实例,class 为必选项的任意已定义的对象类,如果 object 是 class 的一个实例则 instanceof 运算符返回 true,如果 object 不是指定类的一个实例或者 object 是 null 则返回 false;但是 instanceof 在 java 的编译状态和运行状态是有区别的,在编译状态中 class 可以是 object 对象的父类、自身类、子类,在这三种情况下 java 编译时不会报错,在运行转态中 class 可以是 object 对象的父类、自身类但不能是子类,当为父类、自身类的情况下 result 结果为 true,为子类的情况下为 false。
clazz.inInstance(obj) 表明这个对象能不能被转化为这个类,一个对象是本身类的一个对象,一个对象能被转化为本身类所继承类(父类的父类等)和实现的接口(接口的父接口)强转,所有对象都能被 Object 强转,当 obj 参数为 null 时一定为 false。
具体区别可以参见如下例子:
class A {
}
class B extends A {
}
B b = new B();
A a = new A();
A ba = new B();
b instanceof B; //true
b instanceof A; //true
b instanceof Object; //true
null instanceof Object; //false
b.getClass().isInstance(b); //true
b.getClass().isInstance(a); //false
a.getClass().isInstance(ba); //true
b.getClass().isInstance(ba); //true
b.getClass().isInstance(null); //false
A.class.isInstance(a); //true
A.class.isInstance(b); //true
A.class.isInstance(ba); //true
B.class.isInstance(a); //false
B.class.isInstance(b); //true
B.class.isInstance(ba); //true
Object.class.isInstance(b); //true
Object.class.isInstance(null); //false
问:说说 java 的 instanceof 与 clazz.getClass() 的区别?
答:instanceof 进行类型检查规则是你属于该类吗?或者你属于该类的派生类吗?而 obj.getClass() 获得类型信息采用 == 来进行检查是否相等的操作是严格比较,不存在继承方面的考虑。具体区别样例参见如下:
class A {
}
class B extends A {
}
new A() instanceof A; //true
new A() instanceof B; //false
new A().getClass() == A.class; //true
new A().getClass() == B.class; //false
new B() instanceof A; //true
new B() instanceof B; //true
new B().getClass() == A.class; //false
new B().getClass() == B.class; //true
问:简单说说 java 的 instanceof 实现原理?
答:这个题的答案取决于你面试什么岗位,如果是 Android 的话其实如下答案就差不多了,如果是高级后台开发那就需要更加深度的回答了。
首先 instanceof 直接对应一条虚拟机指令 instanceof 且为 java 语法保留关键字,而非通过反射实现;instanceof 在底层实现上维护了主要超类型(继承深度)小于一个固定数值(一般为 7)的主数组和次要超类型(判断的时候需要 super 链遍历查找),然后在字节码使用特殊指令对常量池中的相关符号引用进行判断,从而来决定是否某个类或者派生类,以此返回 true 或 false。