Java 解惑知多少六
41. instanceof与转型
System.out.println(null instanceof String);//false System.out.println(new Object() instanceof String);//false //编译能通过 System.out.println((Object) new Date() instanceof String);//false //!!程序不具有实际意义,但编译时不能通过 //!!System.out.println(new Date() instanceof String); //!!运行时抛ClassCastException,这个程序没有任何意义,但可以编译 //!!System.out.println((Date) new Object());
null可以表示任何引用类型,但是instanceof操作符被定义为在其左操作数为null时返回false。
如果instanceof告诉你一个对象引用是某个特定类型的实例,那么你就可以将其转型为该类型,并调用该类型的方法
,而不用担心会抛出ClassCastException或NullPointerException异常。
instanceof操作符有这样的要求:左操作数要是一个对象的或引用,右操作数是一个引用类型,并且这两个操作数的
类型是要父子关系(左是右的子类,或右是左的子类都行),否则编译时就会出错。
42. 父类构造器调用已重写的方法
public class P { private int x, y; private String name; P(int x, int y) { this.x = x; this.y = y; // 这里实质上是调用子类被重写的方法 name = makeName(); } protected String makeName() { return "[" + x + "," + y + "]"; } public String toString() { return name; } } class S extends P { private String color; S(int x, int y, String color) { super(x, y); this.color = color; } protected String makeName() { return super.makeName() + ":" + color; } public static void main(String[] args) { System.out.println(new S(1, 2, "red"));// [1,2]:null } } 在一个构造器调用一个已经被其子类重写了的方法时,可能会出问题:如果子类重写的方法要访问的子类的域还未初
始化,因为这种方式被调用的方法总是在实例初始化之前执行。要想避免这个问题,就千万不要在父类构造器中调用
已重写的方法。
43. 静态域与静态块的初始顺序
public class T { public static int i = prt(); public static int y = 1; public static int prt() { return y; } public static void main(String[] args) { System.out.println(T.i);// 0 } } 上面的结果不是1,而是0,为什么?
类初始化是按照静态域或静态块在源码中出现的顺序去执行这些静态初始器的(即谁先定义,就先初始化谁),上现程序中由于i先于y声明,所以先初始化i,但由于i初始化时需要由y来决定,此时y又未初始化,实为初始前的值0,所以i的最后结果为0。
44. 请使用引用类型调用静态方法<
public class Outer { public class Inner { public String toString() { return "Hello world"; } } public void getInner() { try { // 普通方式创建内部类实例 System.out.println(new Outer().new Inner());// Hello world //!! 反射创建内部类,抛异常:java.lang.InstantiationException:Outer$Inner System.out.println(Inner.class.newInstance()); } catch (Exception e) { } } public static void main(String[] args) { new Outer().getInner(); } } 上面因为构造内部类时外部类实例不存在而抛异常。
一个非静态的嵌套类的构造器,在编译的时候会将一个隐藏的参数作为它的第一个参数,这个参数表示它的直接外围实例。如果使用反射创建内部类,则要传递个隐藏参数的唯一方法就是使用java.lang.reflect.Constructor:
Constructor c = Inner.class.getConstructor(Outer.class);//获取带参数的内部类构造函数 System.out.println(c.newInstance(Outer.this));//反射时还需传进外围类
ref:http://jiangzhengjun.iteye.com/blog/652762