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 Null {
public static void greet() {
System.out.println("Hello world!");
}
public static void main(String[] args) {
((Null) null).greet();
}
}
上面程序运行时不会打印NullPointerException异常,而是输出"Hello world!",关键原因是:调用静态方法时将忽略前面的调用对象或表达示,只与对象或表达式计算结果的类型有关。
在调用静态方法时,一定要使用类去调用,或是静态导入后直接使用。
45. 循环中的不能声明局部变量
for (int i = 0; i < 1; i++)
Object o ; //!! 编译不能通过
for (int i = 0; i < 1; i++)
Object o = new Object(); //!! 编译不能通过
一个本地变量声明看起来像是一条语句,但是从技术上来说不是。
Java语言规范不允许一个本地变量声明语句作为一条语句在for、while或do循环中重复执行。
一个本地变量声明作为一条语句只能直接出现在一个语句块中(一个语句块是由一对花 括号以及包含在这对花括号中的语句和声明构成的):
for (int i = 0; i < 1; i++) {
Object o = new Object(); // 编译OK
}
46. 内部类反射
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
分享到:
相关推荐
java解惑java解惑java解惑java解惑java解惑java解惑
Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑
Java解惑.pdf Java解惑.pdf Java解惑.pdf Java解惑.pdf
Java解惑中文版 Java解惑 java健壮程序
JAVA解惑.pdf JAVA解惑.pdf JAVA解惑.pdf
你认为自己了解Java多少?你是个爱琢磨的代码侦探吗?你是否曾经花费数天时间去追踪一个由Java或其类库的陷阱和缺陷而导致的bug?你喜欢智力测验吗?本书正好适合你!.. Bloch和Gafter继承了Effective Jaya一书的传统,...
JAVA解惑,你面包括一些java经典的问题。
Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑
与java相关的的学习,适合初学者,可以看看
《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》
《Java解惑》 布洛克 著;陈昊鹏 译 扫描清晰带目录,仅供参阅,请支持正版
"java解惑" PDF版本
讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java程序员阅读。
Java解惑(中文).pdf 给大家介绍java中容易迷惑用错的实例
Java解惑,是一本以大量java实例,讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java...
Java四大名著之一:4,JAVA解惑 高清PDF 下载
该书特写了95个有关Java或其类库的陷阱和缺陷的谜题,其中大多数谜题都采用了短程序的方式,这些程序的行为与其看似的大相径庭。在每个谜题之后都给出了详细的解惑方案,这些解惑方案超越了对程序行为的简单解释,向...
。。。。。 Java解惑(中文) 是一本对 Java一些问题的解答 。。。。。。。。。。
Java解惑,罗列你意想不到的100道java疑惑