快捷搜索:  test  as

对初学者有用的文章

常常听到这样的对话:"你会Weblogic, Oracle, XML, Kylix, 等等吗?不会?你好差。这么先辈的技巧怎么能不会?"每每我们也能在看到很多简历,自称精晓某某,某某某技巧, 乍一看下来,的确是绝顶高手,精晓了所有盛行的先辈技巧。然则我经常想,就算是不用饭不睡觉也弗成能在短短光阴里精晓那么多范围极广,博大年夜博识的技巧啊。而我自己,却经常在实际事情中碰到一些问题,让我不得不想起根基常识的紧张性。我在这里不是要袭击大年夜家进修先辈技巧的热心,而是为了强调一下根基常识的紧张。比如,有很多的java法度榜样员在应用JBuilder, WebLogic, WebSphere, SilverStream,写通俗的java法度榜样或者写j2ee, corba布局的法度榜样。在然则,在掌握先辈技巧的同时,我们也要重视一下根基的修炼,免得赓续呈现本可以避免的差错。我将陆续写一系列的文章,关于java编程常见问题。这些,都是我在日常事情中积累下来的一些条记,不成体系(我只管即便将它们按照范围不合组织一下), 严格的说,不能叫做文章吧。大年夜家随便看看。呵呵。

(内容)

先来看一个常见的差错。

public boolean testAns(String ans, int n){

boolean rslt;

if( ans.equalsIgnoreCase("YES") && n > 5)

rslt = true;

return rslt;

}

法度榜样逻辑方面并没有问题,然则编译的时刻会呈现差错提示

:

variable rslt might not have been initialized

return rslt;

^

这是由于,当if前提为false的时刻,rslt可能会没有被付与初值,而return的时刻则会掉足。java编译器很智慧的反省了这一差错并在编译的时刻给予了提示。这必要你在声明rslt的时刻或者在返回rslt之前给它赋值。

比如:

public boolean testAns(String ans, int n){

boolean rslt = false;

if( ans.equalsIgnoreCase("YES") && n > 5)

rslt = true;

return rslt;

}

相关的问题还有:

public boolean testAns(String ans, int n){

boolean rslt = true;

while(false){rslt = false;}

for(;false;){rslt = false;}

if(false) {rslt = false;}

return rslt;

}

则Java编译器会提示

unreachable statement

while(false){rslt = false;}

^

unreachable statement

for(;false;){rslt = false;}[/code]

^

然则if(false)这一段则没有差错提示,编译经由过程。这也是要留意的一点。

第二个例子:class Object 中有一个措施equals()

public boolean Object.equals(Object) 它反省object reference是否相同,也便是说是否指向同一个工具。假如是,则返回true, 否则返回false. 而每一个承袭class Object的类都邑override这个措施。比如在Long, Integer等class中,equals对照该Ojbect是否响应的是Long, Integer类型。假如类型相同,值对照所包裹的值是否相同。假如相同,则返回true, 否则返回false.要留意的是,返回false并不阐明所包裹的值不相同,也可能是类型不合。比如下面代码:

Long l = new Long(7);

Integer j = new Integer(7);

if(l.equals(j)) System.out.println("Equal");

else System.out.println("Not Equal");

编译成功,然则输出为Not Equal, 这便是由于类型不合, 不是同为Integer或者

同为Long.

再看一下应用instanceof要留意的问题. instanceof是判断一个工具的引用(reference)

是否某一类型。比如

Integer i = new Integer(0);

System.out.println( i instanceof Integer);

返回为true,由于i是一个Integer的工具的引用。

Integer i = new Integer(0);

System.out.println( i instanceof Long);

则返回为false, 由于i不是一个Long的工具的引用。

然则,

Integer i = null;

System.out.println( i instanceof Integer);

返回值为false. 这是由于i的值为null, null不是任何工具的引用。这是必要留意的。

第四个问题,是在邮件列表,news groups中提到次数对照多的一个问题,也是很多初学java编程的人经常碰到的一个问题。以下这段代码,编译会呈现差错。

[code]byte x = 100;

switch(x) {

case 100:

case 200:

case 300:

}

编译器提示

a1.java:6: possible loss of precision

found : int

required: byte

case 200:

^

a1.java:7: possible loss of precision

found : int

required: byte

case 300:

^

2 errors

由于x为byte类型,然则300跨越了byte类型的最大年夜值127, 以是呈现了差错。这段代码相称于是

if(x == 100)

...

else if(x == 200)

...

else if(x == 300)

...

这样子看差错缘故原由就对照显着了。

类似的我们还有这样的代码:

short x = 200;

switch(x) {

case 70000:

case 10:

case 1:

}

编译也会掉足,提示case 7000:这一行类型不匹配。

关于primitive类型的赋值问题,还有以下两个必要留意的问题:

这段代码

byte b = 1;

short s = b;

不会掉足。由于,byte为8 bits, 而short为16 bits,将byte类型的数值付与给short类型的变量不会引起数值精度问题。然则

short s = 1;

byte b = s;

则不能精确编译。由于这样赋值可能导致s所含数值的高8 bit被舍弃,因而数值不精确。这样必要我们在写法度榜样的时刻指定

byte b = (byte)s;

以便看护编译器,"嘿, 假如有精度的丧掉,那是我志愿的,你不必担心!"这样编译就不会掉足了。同样的,

short s = 1;

byte b = 1;

b = b + s;

不能精确编译。必要我们在写法度榜样的时刻指定

b = (byte)(b + s);

这些差错很多人现在都邑避免了。然则这样子的代码是否会编译差错呢?

short s = 1;

byte b = 1;

b += s;

照以上的解释,你必然觉得这段代码不能精确编译。然则假如你实际编译一下则会发明,它编译经由过程了!为什么呢?这是由于, +=, -=, *=, /=, %=这类操作符号对照特殊,对付编译器来说,他们相称于

b += s; -------> b = (byte)(b + s);

呵呵,故意思吧?

inner class的问题,更多的人认为迷惑。

比如,inner class是否能够有static的变量?

一样平常的说法是,static inner class能够有static的变量,而non-static inner

class则不能有static的变量。然则,假如这样:

class outer {

class inner {

static final int i = 999;

}

}

编译经由过程。而你不能这么写:

static final int i;

便是说,必然要在声明它的时刻付与初值, 由于i是final的,它的值不能再被改变。

关于inner class, 还有一个代码也很能阐明一些问题。

public class TestClass

{

public TestClass(int i) { }

public void m1()

{

TestClass al = new TestClass(10)

{

public void actionPerformed(ActionEvent e)

{

}

};

}

}

这阐清楚明了一下四个问题:

1. 类中的措施也可以有inner classes.(然则他们不能有static inner classes).

2. Inner class 能够承袭包孕它的外部class.

3. 匿名 inner class 可以承袭一个 class 或者 implements 一个 interface。

4. 匿名 inner class 可以有初始化参数。(假如这个class承袭的基类有响应的 constructor 的话。)

再来看看动态联编 ( dyanamic link )的问题。

斟酌这段代码:

class base{

public void whoami() {

System.out.println("Base");

}

}

class derived extends base{

public void whoami() {

System.out.println("Derived");

}

}

class test{

public static void main(String[] args) {

base b = new base();

derived d = new derived();

b.whoami();

d.whoami();

base b2 = d;

b2.whoami();

}

}

当然大年夜家很清楚,b.whoami()打印Base, 而d.whoami()打印Derived.然则,b2.whoami()打印什么呢?也便是说,b2.whoami()将调用那一个措施呢?是基类的照样派生类的?运行今后看到,调用的是派生类的措施。这是由于java是在运行历程中采纳了动态联编的措施,在运行时候来抉择该reference指向的什么类的工具,从而抉择调用哪一个类的措施,而不是根据reference的类型来抉择调用哪一个类的措施。从而可以使我们经由过程这一机制来完成多样化的法度榜样。打印的结果将是Derived。

再来看别的一个类似的例子:

class base{

int i = 100;

public void print() {

System.out.println(i);

}

}

class derived extends base{

int i = 999;

public void print() {

System.out.println(i);

}

}

class test{

public static void main(String[] args) {

base b = new base();

derived d = new derived();

b.print();

System.out.print(b.i);

d.print();

System.out.print(d.i);

base b2 = d;

b2.print();

System.out.print(b2.i);

}

}

很简单的,前面的调用:

b.print();

打印100

System.out.print(b.i);

打印100

d.print();

打印999

System.out.print(d.i);

打印999.

然则

System.out.print(b2.i);

打印什么呢?结果是100, 而不是999。这是由于,在动态联编历程中,只是函数介入了,而对付类中的变量,则照样以静态的要领编译的,便是说,编译器是凭借reference的类型来抉择类变量的。b2是base类型的reference, 以是b2.i

是基类中的变量的值。

关于动态联编,还有2个要留意的问题:

class base{

}

class derived extends base{

public void print() {

System.out.println("Derived");

}

}

class test{

public static void main(String[] args) {

base b = new base();

derived d = new derived();

d.print();

base b2 = d;

b2.print();//掉足

}

}

为什么呢?由于在编译历程中,编译器会反省基类中是否有print()措施,假如没有,则会报错。留意:动态联编呈现在运行历程中,而不是编译历程中。

class base{

int i = 100;

public void print() {

System.out.println(i);

}

}

class derived extends base{

int i = 999;

public void print() {

System.out.println(i);

}

}

class test{

public static void main(String[] args) {

base b = new base();

derived d = new derived();

b.print();

System.out.print(b.i);

d.print();

System.out.print(d.i);

base b2 = d;

b2.print();

System.out.print(b2.i);

derived d2 = b;//掉足

d2.print();//掉足

System.out.print(d2.i);//掉足

}

}

这是由于,在编译历程中,derived类型的reference可以赋给base类型的reference.

而base类型的reference则弗成以赋给derived类型的reference.假如要这么做,

则必要在赋值的历程中指定

derived d2 = (derived)b;

编译才能经由过程。这和primitive types的赋值是一样的事理。而编译完成后在运行时候还必要做进一步的查验,假如类型不能匹配,则会抛出

ClassCastException.

Exception in thread "main" java.lang.ClassCastException: base

at test.main(a2.java:12)

......未完,待续

您可能还会对下面的文章感兴趣: