天天看點

Java常見陷阱(一)

 陷阱一:什麼時候“被覆寫的”方法并非真的被覆寫

class Super

{

    static String greeting(){

             return "Super Say Hello";

    }

    String name(){

             return "My Name is Super";

}

class Sub extends Super

             return "Sub Say Hello World";

             return "My Name is Sub";

public class  Test

    public static void main(String[] args)

    {

             Super s1=new Sub();

             System.out.println("Super s1=new Sub():"+s1.greeting()+",\t"+s1.name());

             Super s2=new Super();

             System.out.println("Super s2=new Super()"+s2.greeting()+",\t"+s2.name());

             Sub s3=new Sub();

             System.out.println("Sub s3=new Sub():"+s3.greeting()+",\t"+s3.name());

             //Sub s4=new Super();//錯誤

             //System.out.println("Sub s4=new Super():"+s4.greeting()+",\t"+s4.name());

結果:

Super s1=new Sub():Super Say Hello,     My Name is Sub

Super s2=new Super()Super Say Hello,    My Name is Super

Sub s3=new Sub():Sub Say Hello World,   My Name is Sub

         記住一個原則:“<b>執行個體方法被覆寫,靜态方法被隐藏”</b>。

陷阱二:String.equals()方法與“==”運算符的用法比較

    class Test

             String s1="language";

             String s2=new String("language");

             String s3="langu"+"age";

             System.out.println("s1.equals(s2):"+s1.equals(s2));

             System.out.println("s1.equals(s3):"+s1.equals(s3));

             System.out.println("s2.equals(s3):"+s2.equals(s3));

             System.out.println("s1==s2:"+(s1==s2));

             System.out.println("s1==s3:"+(s1==s3));

             System.out.println("s2==s3:"+(s2==s3));

s1.equals(s2):true

s1.equals(s3):true

s2.equals(s3):true

s1==s2:false

s1==s3:true

s2==s3:false

         String.equals()方法比較的是字元串的内容。使用equals()方法,會對字元串中的所有字元,一個接一個地進行比較,如果完全向導,那麼就會傳回true。運算符“==”比較的是String執行個體的引用。當字元串由多個字元串常量連接配接而成時。如s3,他同樣在編譯期就被解析稱為一個字元串常量。Java會設定兩個變量的應用為同一個常量的引用。在常量池中,Java會跟蹤所有的字元串常量。

         常量池指的是在編譯期被确定,并儲存在已編譯的.class檔案中的一些資料。它包含了有關于方法、類、接口等等,當然還有字元串常量的資訊。當JVM裝載了這個.class檔案,變量s1和s3被解析,JVM執行了一項名為常量池解析的操作。該項操作針對字元串的處理過程,百科一下步驟:

Ø  如果另一個常量池入口被标記為CONSTANT_String,并且指出,同樣的Unicode字元序列已經被解析,那麼這項操作結果就是之前的常量池入口建立的String執行個體的引用。

Ø  否則,如果intern()方法已經被這個常量池描述的一個包含同樣Unicode字元序列的String執行個體調用過,那麼這項操作的結果就是那個相同String執行個體的引用。

Ø  否則,一個新的String執行個體會被建立。它包含了CONSTANT_String入口描述的Unicode字元序列;這個String執行個體就是該項操作的結果。

import java.io.*;

class  StringTest

        public static void main(String[] args) throws Exception

        {

                 String sFile ="out.txt";

                 String s1=readerStringFile(sFile);

                 String s2=readerStringFile(sFile);

                 System.out.println("s1==s2:"+(s1==s2));

                 System.out.println("s1.equals(s2):"+s1.equals(s2));

                 s1.intern();

                 s2.intern();

                 System.out.println("s1==s2.intern():"+(s1==s2.intern()));

        }

        public static String readerStringFile(String sFile)throws Exception{

                 File f=new File("D:\\"+sFile);

                 FileInputStream iput=new FileInputStream(f);

                 byte b[]=new byte[(int)f.length()];//将所有内容都讀入此數組之中

                 for(int i=0;i&lt;f.length();i++)

                 {

                          b[i]=(byte)iput.read();

                 }

                 iput.close();

                 String ss=new String(b);

                 return ss;

s1==s2.intern():true

         總的來說,在執行等式比較時,應該實戰使用String.equals()方法而不是“==”運算符語句String.equals()和String.intern()得到的結果是一緻的。

陷阱三:Java是強制類型的語言

         平時看到的诶呀辨別類型的數值如1,2,765等等均可以看做int類型,若辨別了1l,34d,54f等等就不能看做int類型而是看成它們特有的類型。

陷阱四:那是構造函數嗎?

         構造函數是沒有傳回類型的,而且構造函數是不能用static,final,abstract等關鍵字修飾。

         每一個類都有構造函數,隻是有的是隐性的,我們看到的是顯式的構造函數。構造函數是可以多态的。構造函數也使可以用privata修飾的。

陷阱四:不能通路被覆寫的方法

         可以通過包含關鍵字super的方法調用表達式來通路被覆寫的方法。注意:嘗試用全局名或強制轉換為分類型,以求通路一個被覆寫的,是無效的。

         無法通路中被子類覆寫的方法原則,僅僅适用于執行個體方法,也就是非靜态方法。即使父類中的靜态方法被子類“覆寫”(并非真正的覆寫,而是子類也具有與父類中同名的方法)了,它們仍然能被被通路。強制轉換為父類的類型就能達到這個目的。

陷阱五:避免落入“隐藏變量成員”的陷阱

public class  WWW

         public  String s="Hello Java";

         public  void  wMM(){

                  System.out.println("***"+s+”***”);

         }

         public static void main(String[] args)

         {

                   WWW w=new WWW();

                   w.wMM();

         public static String s="Hello Java";

         public static void  wMM(){

                  System.out.println("***"+s+"***");

         public void mWW(){

                   wMM();

                   w.mWW();

         結果1:          ***Hello Java***

         結果2:          ***Hello Java***

***Hello Java***

         非靜态方法可以調用非靜态方法和靜态方法,但是靜态方法不可調用非靜态方法。

不同類型的Java變量

         Java一共有6種變量類型:

Ø  類變量:包括在類中聲明的靜态資料成員以及在接口體中聲明的靜态或非靜态資料成員。

Ø  執行個體變量:在類中聲明的非靜态變量。

Ø  方法參數:是用來傳入一個方法體的。

Ø  構造函數參數:是用來傳入一個構造函數體的。

Ø  異常處理器參數:用來傳入一個try語句的catch塊中的。

Ø  局部變量:是在一個代碼塊中或一個for語句中聲明的變量。

注意:變量成員是指類變量和執行個體變量。

變量的作用範圍

         變量的作用範圍指的其實是一塊代碼塊。

         執行個體變量和類變量的作用範圍就是它們的類或接口的整體。

         方法參數的作用範圍就是整個方法體。

         構造函數參數作用範圍就是整個構造函數體。

         異常處理器參數作用範圍是catch語句。

         局部變量的作用範圍是它被聲明的所在代碼塊。

何種變量能被隐藏

         執行個體變量和類變量能被隐藏。局部變量和各種參數永遠不會被隐藏的。假如用一個同名的局部變量去隐藏一個參數,編譯器将會報錯。

   public class Test

   public static void mWW(String s){

            String s="Hello Java"; //錯誤

   }

   public static void main(String[] args)

   {

            mWW("******");

                   結果:Test.java:4: 錯誤: 已在mWW(String)中定義s

                         String s="Hello Java";

執行個體變量和類變量如何被隐藏

         同名的局部變量或者同名的參數,可以隐藏掉變量成員的一部分作用範圍,變量成員也能被子類的同名變量成員隐藏。與一個變量成員同名的局部變量,将在其作用範圍内,隐藏掉這個成員變量。與一個變量成員同名的方法參數,将在方法體中隐藏掉這個變量成員。與一個變量成員同名的構造函數參數,将在構造函數體中隐藏掉這個變量成員。以此類推,與一個變量成員同名的異常處理器參數,将在catch語句塊中隐藏掉這個變量成員。

如何通路被隐藏的變量

         通過全局名,可以通路大多數的變量成員。關鍵字“this”可以限定一個正被局部變量隐藏的執行個體變量。關鍵字“super”可以限定一個正被子類隐藏的執行個體變量。類變量特可以被限定,隻要在該類的名字與該類變量的名字之間加上“.”即可。

變量隐藏與方法隐藏的差別

         它們之間最重要的差別是:一個類的執行個體,無法通過使用全局變量,或者強制轉換自己為其父類的類型,以通路其父類中被覆寫的方法。

         資料覆寫與方法覆寫的另外一個不同就是靜态方法不能覆寫父類的執行個體方法,而靜态變量卻可以隐藏父類的一個同名執行個體變量。相同地,執行個體方法也不能覆寫父類的同名方法靜态方法,而變量成員卻可以隐藏父類同名變量成員,不論父類的這個同名變量成員是類還是執行個體變量。

本文轉自 夢朝思夕 51CTO部落格,原文連結:http://blog.51cto.com/qiangmzsx/852877