Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » Java SE 综合讨论区  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 [转贴]对初学者很有用的文章
jinco



发贴: 0
积分: 0
于 2004-03-25 09:41 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
经常听到这样的对话:"你会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;}
^

但是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编程的人常常遇到的一个问题。以下这段代码,编译会出现错误。
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)

......未完,待续

呵呵,同志们,这是一位高手的力作。可不是本人的原创。


why edited on 2004-03-27 20:38

作者 Re:[转贴]对初学者很有用的文章 [Re:jinco]
caoyi





发贴: 32
积分: 0
于 2004-03-27 17:44 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
排版不是很舒服


作者 Re:[转贴]对初学者很有用的文章 [Re:jinco]
PrimeJava

一切皆有可能



发贴: 142
积分: 15
于 2004-03-27 20:28 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
有同感!


I Believe I can fly!
作者 Re:[转贴]对初学者很有用的文章 [Re:jinco]
bluepure

pureblue



发贴: 509
积分: 85
于 2004-03-29 11:05 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
public boolean testAns(String ans, int n)
{ boolean rslt;
if( ans.equalsIgnoreCase("YES") && n > 5)
rslt = true;
return rslt;}


为什么不这样写呢:


public boolean testAns(String ans, int n)
{
return ans.equalsIgnoreCase("YES") && n > 5;
}


一行代码就可以了。



作者 Re:[转贴]对初学者很有用的文章 [Re:bluepure]
hohaischooldays





发贴: 112
积分: 10
于 2004-03-30 16:00 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
bluepure wrote:
public boolean testAns(String ans, int n)
{ boolean rslt;
if( ans.equalsIgnoreCase("YES") && n > 5)
rslt = true;
return rslt;}


为什么不这样写呢:


public boolean testAns(String ans, int n)
{
return ans.equalsIgnoreCase("YES") && n > 5;
}


一行代码就可以了。

很好,高!够灵活!



作者 Re:[转贴]对初学者很有用的文章 [Re:jinco]
fangquan



发贴: 0
积分: 0
于 2004-04-06 15:27 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
支持!
public gfsfstret trhgjgk




flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923