关闭

Java 拾遗

929人阅读 评论(0) 收藏 举报

最近在工作中,经常发现java中的一些小细节,自己以前都没有注意,发现之后还是有点新鲜的,不过都是很基础的东西(也许是自己java基础太过薄弱,嘿嘿),就记录在这里,以予自乐。

 

1、  方法重载的问题

 

public class Test {
    
private Test(Object o) {
        System.out.println(
"Object");
    }

    
    
private Test(double[] o) {
        System.out.println(
"double array");
    }


    
public static void main(String[] args) {
        
new Test(null);
    }

}

 

上述代码的输出结果会是什么呢?"Object""double array"?还是其它?

答案是"double array",由于null的特殊性,在这里看似既符合Object有符合double[],但是java的设计者似乎懂得近水楼台先得月这个俗语,于是java对象的匹配顺序是从低层次到高层次,数组对象继承于Object,也就是层次比Object低,因此这里输出的是"double array"而不是"Object"

 

2、奇数的问题

是否能用下面的方法确定其唯一参数是奇数?

public static boolean isOdd(int i) {
        System.out.println(i 
% 2);
        
return i % 2 == 1;
    }

看到这个你就会想到小学老师教的“能被2整除的是偶数,不能被2整除的是奇数”,于是乎很自然的就认为这是正确的。那么我告诉你正确答案:错!大错特错!翻翻教科书,奇数跟偶数的概念只适用于自然数,而这里的参数iint型的,它包含了负数,因此也就错了!(TX们,看书要仔细啊!)

3、无符号右移的问题

while (i != 0{
            i 
>>>= 1;
        }

上面的代码中,要声明怎样的一个i,才能使循环变成无限循环?

很难想吧?那就提供几个选项缩小范围吧:

A short i = -1

B int i = -1

C long i = -1L

D byte i = -1

E char i = 1

还是不知道答案吧?那就告诉你吧,答案应该是AD

>>>”在java中被称为:“无符号”右移位运算符,它使用了“零扩展”:无论正负,都在高位插入0。而对charbyte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int,因此“零扩展”不再发生,于是AD无论怎么移始终都等于-1,也就变成了无限循环。

 

4try-catch的问题

public class Test {

    
public static void main(String[] args) {
        
try {
            System.out.print(
"1");
            Runtime.getRuntime().addShutdownHook(
new Thread() {
                
public void run() {
                    System.out.print(
"2");
                }

            }
);
            System.exit(
0);
        }
 finally {
            System.out.print(
"3");
        }

    }

}

上面的代码有错吗?错在哪?如果没有错,那么其输出结果又是什么?

答案:代码没有错,其输出结果是“12”。

很出乎意料是不是?如果不是真的运行了程序,相信很多朋友都说不出正确结果,这么短短的一段代码却藏着多处陷阱。“try后必须紧跟至少一个catch,“finally的代码无论如何都要执行…”,相信很多朋友都可以这么背出来。但是真实的情况如你所见,try可以跳过catch直接跟finally的,而且finally的代码也有不被执行的情况。不明白?那你再仔细看看那句System.exit(0)吧,它意味着什么呢?执行它就代表你的程序(线程)结束,既然程序都结束了,finally当然就执行不到了,这跟return是有区别的,要特别注意!

 

既然提到try的问题,那就顺便把在网上看到的另外一篇介绍try之古怪的文章转过来吧,相信你看了后会大跌眼镜!

原帖:http://ajaxgo.javaeye.com/blog/118979

==========================以下内容为转载===============================

 

今天无意中,同事发现了一个有趣的现象,首先来看一下以下代码:

 

java 代码会发现,18行加载了一下变量b中的值,所以,其实,在执行代码的第8行时,并不是执行return,而只是往内存中存储变量b的值。

 

public class Test {    
    
private static int todo() {    
        
int b=1;    
        
try{    
            
int a=2/0;    
        }
 catch(Exception e) {    
            System.out.println(
"in catch"); 
            
return 1;    
        }
 finally {    
            System.out.println(
"in final");    
        }
    
        
return 2;    
    }
    
    
/**   
     * 
@param args   
     
*/
   
    
public static void main(String[] args) {    
        System.out.println(todo());    
   
    }
    
}
   

此时,运行结果为

in catch

in final

1

 

看到这里,少部分人已经开始不明白了,我们继续看另一则代码(请注意细小的差别):

 

java 代码

public class Test {       
    
private static int todo() {       
        
int b=1;       
        
try{       
            
int a=2/0;       
        }
 catch(Exception e) {       
            System.out.println(
"in catch");    
            
return b;       
        }
 finally {       
            System.out.println(
"in final");       
        }
       
        
return 2;       
    }
       
    
/**     
     * 
@param args     
     
*/
      
    
public static void main(String[] args) {       
        System.out.println(todo());       
      
    }
       
}
    

此时,运行结果依旧是

in catch

in final

1

 

但是通过单步执行,会发现,两种代码的执行顺序有少许差别

 

第一种代码的try/catch单步执行顺序为

7->10->8

 

第二种代码的try/catch单步执行顺序为

7->8->10->8

 

 

这里我们对其进行了研究,从中间码入手,首先来分别看看两者的中间码:

 

 

上述第一块代码的中间码

11  ldc "in catch"> [22]   

13  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   

16  getstatic java.lang.System.out : java.io.PrintStream [16]   

19  ldc "in final"> [30]   

21  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   

24  iconst_1   

25  ireturn  

 

可以发现,明显的执行顺序,1行把装入字符串转入内存,2行打印,4行在把字符串装入内存,5行再打印,7行返回

 

上述第二块代码的中间码

13  ldc "in catch"> [22]   

15  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   

18  iload_0 [b]   

19  istore_3   

20  getstatic java.lang.System.out : java.io.PrintStream [16]   

23  ldc "in final"> [30]   

25  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   

28  iload_3

29  ireturn  

 

 

 

以上的过程,分析下中间码,还是可以理解的,但是非常非常让人奇怪的是,如下的代码(请还是注意不同的细节)

 

java 代码 

public class Test {          
    
private static int todo() {          
        
int b=1;          
        
try{          
            
int a=2/0;          
        }
 catch(Exception e) {          
            System.out.println(
"in catch");       
            
return b;          
        }
 finally {   
            b
=3;        
            System.out.println(
"in final");          
        }
          
        
return 2;          
    }
          
    
/**       
     * 
@param args       
     
*/
         
    
public static void main(String[] args) {          
        System.out.println(todo());          
         
    }
          
}
    

此时运行结果照样是

in catch

in final

1

 

单步执行结果是 7->8->10->11->8

想不通的是,根据单步执行,在finally里对b进行了修改,但是,返回的仍旧是1

 

再来看看这个代码的中间码:

 

第三个代码的中间码

13  ldc "in catch"> [22]   

15  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   

18  iload_0 [b]   

19  istore_3   

20  iconst_3   

21  istore_0 [b]   

22  getstatic java.lang.System.out : java.io.PrintStream [16]   

25  ldc "in final"> [30]   

27  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   

30  iload_3   

31  ireturn  

 

因为,其实我没怎么学过汇编,只是初步的分析了

3行加载b的地址,4行在地址3储存b的值(此时地址3的值为1),5行加载一个常量,6行把常量存入b的地址(此时b的值为3),10行加载地址3的值,最后返回值。

不知道这样的解释是否合理,也请,希望能够得到一个对于try./catch块执行问题的通俗答案,谢谢!

 

==========================以上内容为转载===============================

 

好了,由于时间关系,本次拾遗就到此结束了,以后会陆续补充些其它经典问题上来,一来供自己备忘,二来给java初学者一些警示,希望通过此文能减少大家编码时出现的错误!哪怕是有一位朋友觉得有用,我也会非常高兴!

 

Java咖啡群欢迎大家加入(加群者送分,顶帖者也送分哈),群号:60446231
本群以讨论IT行业话题为主,本着交流信息的原则,为大家营造一个轻松欢娱的环境,给平时枯燥的工作增添一些调味剂.
当然,技术问题同样在讨论范围之中.
本人在这里欢迎大家的到来,并预祝大家五一快乐.(鼓掌...谢谢...嘿嘿...)
 
Java基础群:49827836
java初学者提供帮助,在讨论及解决问题中共同成长。
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:24583次
    • 积分:372
    • 等级:
    • 排名:千里之外
    • 原创:9篇
    • 转载:2篇
    • 译文:1篇
    • 评论:8条
    最新评论