Java編程思想學習雜記(1-4章)

  • 2020 年 3 月 30 日
  • 筆記

程序流程控制

移位運算符

移位運算符面向的運算對象是二進制的位,可單獨用它們處理整數類型。左移位運算符(<<)能將運算符左邊的運算對象向左移動運算符右側指定的位數(在低位補0)。「有符號」右移位運算符使用了「符號擴展」:若值為正,則在高位插入0;若值為負,則在高位插入1。Java也添加了一種「無符號」右移位運算符(>>>),它使用「零擴展」:無論正負,都在高位插入0。若對char, byte或者short進行移位處理,那麼在移位進行之前,它們會自動轉換成一個int。只用右側的5個低位才會用到。這樣可防止我們在一個int數里移動一個不切實際的位數。若對一個long值進行移位,最後得到的結果也是long型。此時只會用到右側6個低位,防止移動超過long值現成的位數。但在進行「無符號」右移位時,也可能遇到一個問題,若對byte和short值進行又移位運算,得到的可能不是正確的結果。它們會自動轉換成int類型,並進行右移位。但「零擴展」不會發生,所以在那些情況下會得到-1的結果。

移位可與等號(<<=或>>=或>>>=)組合使用。此時,運算符左邊的值會移動由右邊的值指定的位數,再將得到的結果賦值回左邊的值。

public class Test {      public static void main(String[] args) {          int i = 8;          i >>= 2;          System.out.println(i);          i <<= 1;          System.out.println(i);          i <<= 1;          System.out.println(i);          i >>>= 1;          System.out.println(i);          i >>>= 1;          System.out.println(i);      }  }  // output  /*  2 4 8 4 2  */  

三元運算符

布爾表達式 ? 值0 : 值1

public class Test {      public static void main(String[] args) {          int i = 10;          System.out.println(i < 10 ? 5 : 11);          System.out.println(i == 10 ? i / 2 : 0);      }  }  // output  /*  11 5  */  

表達式運算符優先級
一元運算符 > 算術(移位)運算符 > 關係運算符 > 邏輯(按位)運算符 > 條件運算符 > 賦值

  • 一元運算符:++、–
  • 算術(移位)運算符:*、/、%、+、-、<<、>>
  • 關係運算符:>、<、>=、<=、==、!=
  • 邏輯(按位)運算符:&&、||、&、|、^
  • 條件(三元):A>B?X:Y
  • 賦值:= (以及複合賦值,如*=)

Java中goto標籤的使用

儘管goto的濫用會導致程序的不可讀,但是在一些情況下,goto是組織控制流程的最佳手段,因此很多的語言中仍然或多或少地保留了其一些用法,對Java來說,唯一用到標籤的地方就是在循環語句之前。

public class Test {      public static void main(String[] args) {          int i = 0;          outer:          for (;true;){              inner:              for (;i < 10;i++){                  System.out.println("i = " + i);                  if (i == 2){                      System.out.println("continue");                      continue ;                  }                  if (i == 3){                      System.out.println("break");                      i++;                      break ;                  }                  if (i == 7){                      System.out.println("continue outer");                      i++;                      continue outer;                  }                  if (i == 8){                      System.out.println("break outer");                      break outer;                  }                  for (int k = 0; k < 5;k++){                      if (k ==3) {                          System.out.println("continue inner");                          continue inner;                      }                  }              }          }        }  }  // output  /*  i = 0  continue inner  i = 1  continue inner  i = 2  continue  i = 3  break  i = 4  continue inner  i = 5  continue inner  i = 6  continue inner  i = 7  continue outer  i = 8  break outer  */  

需要注意的是當你使用switch…case語句時,遇到滿足的一個case之後,如果之後沒有break,將會繼續執行接下來的語句而不會管符不符合之後條件,直到遇到break語句或者程序片段執行完畢。一般應該在switch…case語句之中,最後放置一個default條件,以執行沒有備選條件下的任務。

public class Test {      public static void main(String[] args) {          int i = 5;          switch (i){              case 3:                  System.out.println("case3: " + i);              case 5:                  System.out.println("case5: " + i);              case 7:                  System.out.println("case7: " + i);              default:                  System.out.println("default: " + i);          }      }  }  // output  /*  case5: 5  case7: 5  default: 5  */  
public class Test {      public static void main(String[] args) {          int i = 5;          switch (i){              case 3:                  System.out.println("case3: " + i); break;              case 5:                  System.out.println("case5: " + i); break;              case 7:                  System.out.println("case7: " + i); break;              default:                  System.out.println("default: " + i); break;          }      }  }  // output  /*  case5: 5  */  

需要注意的是switch要求的選擇因子必須是int或char的整數值。而假如將一個字符串或者浮點數作為選擇因子使用,那麼它們在switch語句中是不會工作的。

Math.random()會產生0-1之間的值,其範圍為[0, 1)。

當我們使用構造器的時候,如果我們自己並沒有在類中進行任何定義,則系統會替我們創建一個默認的無參構造器,而當我們定義了任何一個構造器時,無論有沒有參數,系統都不會再繼續幫我們進行創建無參構造器。

註:儘管我們可以在非靜態方法中訪問靜態方法和靜態變量,但是反過來卻是不行的。因為靜態數據的構造要優先於非靜態方法。

Java中使用垃圾收集器回收由不再使用的對象佔據的內存。但是垃圾收集器只知道釋放那些由new分配的內存,所以不知道如何釋放對象的「特殊」內存。為解決這一問題,Java提供了一個名為finalize()的方法,可為我們的類定義它。在理想情況下,它的工作原理應該是這樣的:一旦垃圾收集器準備好釋放對象佔用的存儲空間,它首先調用finalize(),不過只有在下一次垃圾收集過程中,才會真正回收對象的內存。所以如果使用finalize(),就可以在垃圾收集期間進行一些重要的清除或清掃工作。

垃圾收集只跟內存有關,也就是說垃圾收集器存在的唯一原因就是為了回收程序不再使用的內存。

finalize()最有用的地方之一就是觀察垃圾收集的過程。

在一個類里,初始化順序是由變量在類內的定義順序決定的。即使變量定義大量遍佈於方法定義的中間,那些變量仍會在調用任何方法之前得到初始化(甚至在構建器調用之前)。