2015年11月29日 星期日

字串比較 == 與 equals

在JAVA的字串比較中:
 ==      用來比對是否兩個字串指向同一個物件
equals 用來比對字串內容是否相同

String s1 = "JAVA";
String s2 = "JAVA";
String s3 = new String("JAVA");
String s4 = new String("JAVA");

其中:

s1 == s2  //true 由於物件池的存在 s1與s2的宣告方式 其實會指向同一個字串物件
s1.equals(s2) //true 內容相同
s3 == s1 //false 不同物件
s3.equals(s1) //true 內容相同
s3 == s4 //false 不同物件
s3.equals(s4) //true 內容相同


何謂字串池?

在Java1.4之後,為了提升字串的使用與效能,特別為字串在記憶體中(的Heap區 )建立了一個虛擬的物件池來存放字串。凡是直接指定字串的宣告,如s1與s2,其字串物件都會被放進字串池中。
字串池有個特點就是,相同的字串內容不會被重複建立字串物件,所以上面的s1與s2會是相同的物件,而s3與s4由於並沒有被存放在物件池中,所以實際上是兩個不同的物件。


注意:

由StringBuilder建立的物件是StringBuilder物件不是字串物件,所以不應該直接用equals與字串做比較,一般是使用toString()方法後再與字串比較。

StringBuilder s1 = new StringBuilder("Test");
String s2 = "Test";

其中:

s1 .toString().equals(s2); //true 內容相同

2015年11月18日 星期三

Java的覆寫與遮蔽

當子類別重新定義父類別的方法時稱之為覆寫
當子類別重新定義父類別的屬性時稱之為遮蔽

當子類別物件被轉型為父類別時
使用覆寫的方法時會呼叫子類別中定義的方法
使用遮蔽的屬性時會使用父類別中定義的屬性
但依舊可以在物件內部使用super來使用父類別定義的方法與屬性
 package learning.test;

public class overloadtest {
 public static void main(String[] args) {
  Banana mybanana = new Banana();
  System.out.println(mybanana.name);
  System.out.println(mybanana.getName());
  System.out.println(((Banana) mybanana).name);
  System.out.println(((Banana) mybanana).getName());
  System.out.println(((MyFruit) mybanana).name);
  System.out.println(((MyFruit) mybanana).getName());
 }
}

class MyFruit {
 String name = "Fruit";

 String getName() {
  return name;
 }
}

class Banana extends MyFruit {
 String name = "Banana";

 String getName() {
  return name;
 }
}
輸出:
在程式第10行中將物件轉型為MyFruit型態,其name屬性輸出為Fruit。
在程式第11行中將物件轉型為MyFruit型態,但其getName()方法輸出為Banana。
Banana
Banana
Banana
Banana
Fruit
Banana

2015年11月16日 星期一

JAVA的不定長度引數

1. 格式:function ( type... variableName)
    例: public int test(int... x)

2. 不定長度引數必然為參數列的最後一個參數
    例:  public int test(int x, int... y)  -- 可
    例:  public int test(int... x, int y)  -- 不可

3. 參數列中只能有一個不定長度引數
    例:  public int test(int x, int... y)  -- 可
    例:  public int test(int... x, int... y)  -- 不可

4. JAVA的不定長度引數其實只是編譯器蜜糖,本質是陣列展開。

2015年11月7日 星期六

Java的Stream.reduce()

Java SE8 技術手冊(好書一本) 12-35頁有段程式碼是這頁樣寫的
int sum = employees.stream()
          .filter(employee ->employee.getGender() == Gender2.MALE)
          .mapToInt(Employee2::getAge)
          .reduce((total,age) -> total + age)
          .getAsInt();
該書還有句話是這麼說的,若是reduce()沒有指定初值,就會試著使用該組數據中第一個元素作為第一次呼叫Lambda表示式時的第一個引數值
老實說我第一次看到就想說這樣第一的值不是被重複計算了嗎?
(第一個引數是上次運算結果,第二個引數是目前走訪的元素)
所以查了一下API文件發現,reduce()的作用大概同等於(但不限制為按順序執行。):
     boolean foundAny = false;
     T result = null;
     for (T element : this stream) {
         if (!foundAny) {
             foundAny = true;
             result = element;
         }
         else
             result = accumulator.apply(result, element);
     }
     return foundAny ? Optional.of(result) : Optional.empty();
所以大概可以想成 第一個引數直接指定成該組數據中的第一個元素吧! (如果有的話)
我寫了一個測試程式發現 迭代的第一次確實沒有進去執行reduce中的lambda表示式。
(或許應該說第一次執行時就將該組數據中第一個元素當成lambda表示式的第一個引數,第二個元素當成lambda表示式的第二個引數。)
package learning.test;

import java.util.Arrays;
import java.util.List;

public class StreamTest {
 public static void main(String[] args) {
  List&ltEmployee&gt employees = Arrays.asList(new Employee(10),
    new Employee(20), new Employee(30), new Employee(50));
  int sum = employees.stream().filter(employee -&gt employee.getAge() &gt 10)
    .mapToInt(Employee::getAge).reduce((total, age) -&gt {
     System.out.println("age=" + age);
     System.out.println("total=" + total);
     System.out.println("-----------");
     return total + age;
    }).getAsInt();
  System.out.println(sum);
 }
}

class Employee {
 int age;

 Employee(int a) {
  age = a;
 }

 public int getAge() {
  return age;
 }
}
輸出結果:
age=30
total=20
-----------
age=50
total=50
-----------
100

2015年11月5日 星期四

泛型中的<? super T> <? extends T> 是什麼意思

這裡不在多做解釋泛型了

? super T       代表T及其父類別
? extends T    代表T及其子類別

假設現在有一個Goblin類別繼承Monster類別
那麼你可以這樣實例化:


  List<Goblin> goblinList1= new ArrayList<Goblin>();
  List<Monster> goblinList2= new ArrayList<Monster>();

  List<? super Goblin> goblinList3 =  new ArrayList<Goblin>();
  List<? super Goblin> goblinLis4 =  new ArrayList<Monster>();
  List<? super Goblin> goblinList5 =  new ArrayList<Object>();

  List<? extends Monster> goblinList6 =  new ArrayList<Monster>();
  List<? extends Monster> goblinList7 =  new ArrayList<Goblin>();


......

看一下Java SE8 中 Iterable<T> 介面新增的預設方法,就是這樣宣告的..

forEach(Consumer<? super T> action)

2015年11月2日 星期一

自動產生Java API 文件檔

這超好用
就算不是在寫公用API
也可以寫給自己用
可以自動產生網頁版的API文件
這裡示範一個簡單的用法:

1. 使用 /** --*/ 為程式碼下注解
示範用類別:
package learning.test;

import java.util.ArrayList;

public class InventorySystem {
 /** 道具欄的總格數 */
 int totalGrid;
 /** 物品儲存List */
 ArrayList&ltObject&gt al;

 /** 建構函式 */
 public InventorySystem(int totalGrid) {
  super();
  this.totalGrid = totalGrid;
  al = new ArrayList&ltObject&gt(totalGrid);
 }

 /** 將物品放入道具欄 */
 public static boolean putItem(Object item) {
  return true;
 }

 /** 藉由物品id取得物品 */
 public static Object getItemObjectById(int id) {
  return new Object();
 }

 /** 藉由物品id取得物品數量 */
 public static int getItemNumberById(int id) {
  return 520;
 }
}

2.Eclipse 上選Project -> Generate Javadoc