Android Studio代码检查的问题
看下面一段代码:
public class Car2 implements Serializable {
}
public class Car3 {
}
public class JavaDemo2 {
public static void main(String[] args) {
}
public void test(Serializable s) {
if (s instanceof Car2) {
} else if (s instanceof Car3) {
}
}
}
注意test
方法的参数是Serializable
类型,但Car3
类并没有实现Serializable
接口。此时可以编译并运行。
修改代码,给Car3
类添加final
修饰符
public final class Car3 {
}
此时再看test
方法:
![](https://img.haomeiwen.com/i4272648/f3bbdcaab7827089.png)
Android Studio提示不可转换的类型,编译失败。
刨根问底
对于这个现象,一开始没有深入分析,因为在我们的使用场景中,这就是个bug。所以以为是IDE的处理不够完善。然而仔细分析才发现,是自己图样图森破了。
Car3
如果没有final
修饰的话,完全可以构造一个Car4
类:
public class Car4 extends Car3 implements Serializable {
}
将Car4
的实例传给test
方法,就进入了else if
分支。而当Car3
有final
修饰符时,自然就不会有Car4
这个子类了,所以会报编译错误。
类型擦除那点事
代码中的问题可以抽象成一个简单的例子。有两个类:Teacher
和Student
:
public static class Teacher {
private final String name;
public Teacher(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
}
public static class Student {
private final String name;
public Student(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
各有一个name
变量,没什么好解释的。然后重点来了:
public static void main(String[] args) {
List<Teacher> teachers = new ArrayList<>();
teachers.add(new Teacher("teacher1"));
teachers.add(new Teacher("teacher2"));
Object obj = teachers;
List<Student> students = (List<Student>) obj;
for (Object object : students) {
System.out.println(object);
}
}
编译、运行都没有问题。输出如下:
Teacher{name='teacher1'}
Teacher{name='teacher2'}
哎呀,List<Student> students = (List<Student>) obj;
竟然没报错,惊不惊喜,意不意外?不仅如此,for循环从students中取出的竟然是Teacher
类!
这是一个很典型的类型擦除的示例,查看反编译的class文件就一目了然了:
public static void main(String[] var0) {
ArrayList var1 = new ArrayList();
var1.add(new JavaDemo2.Teacher("teacher1"));
var1.add(new JavaDemo2.Teacher("teacher2"));
List var3 = (List)var1;
Iterator var4 = var3.iterator();
while(var4.hasNext()) {
Object var5 = var4.next();
System.out.println(var5);
}
}
可以看到,list的类型被擦除,难怪强转在运行时不会报错。而obj
变量在编译期无法确定具体类型,自然在编译期也就不会报错了。
类型擦除算是Java的必修课,不过在实际coding中很少会注意到。通过这个问题,才发现原来有好多的思维定式需要改变。
IDE不报错,不代表程序就是合格的。
网友评论