2013年11月24日 星期日

Eclipse 設定編碼方法

      當你載入其他人開發的專案或檔案時,有時會發現奇怪的字元時,就表示你的 Eclipse 預設的編碼方式與專案不同。 Eclipse IDE 提供三種設定編碼的方式:

  1. 設定單一檔案的編碼:只有該檔案被設定此編碼。
  2. 設定單一專案的編碼:只有所選的專案設定為此編碼。
  3. 預設所有專案的編碼:所有你新開的專案都以此設定為主,在 Windows 平台建議選擇 UTF-8 (繁體 Windows上 Eclipse 預設使用 MS-950 編碼 ),這樣切換到 Linux 上才不會要再設定一次。
      這三種設定的方式請參考下面的圖示:

  • 設定單一檔案的編碼


    • 設定專案的編碼
    • 預設所有專案的編碼

    [延伸閱讀]
         

    2013年11月17日 星期日

    解決 HTC One SV 更新後 "開發者選項" 不見的問題

        昨天更新我的 HTC One SV 後,今天發現開發者選項竟然不見了,上網查到的解決方式如下:
              設定>關於>軟體資訊>更多>狂按 建置號碼


    參考資料:

    旋轉 Windows 畫面

        今天電腦讓小朋友亂按,結果開始列跑到右邊去,上網查了一下如何旋轉畫面,終於把畫面給轉回來了~: )

        如果你想要旋轉 Windows 畫面可以透過下面的 Shortcut Key:
    1. Ctrl + Alt + Up Arrow  (這是我們一般操作的畫面 開始列在下方)
    2. Ctrl + Alt + Down Arrow (開始列在上面,畫面上下顛倒)
    3. Ctrl + Alt + Right Arrow (開始列在右邊)
    4. Ctrl + Alt + Left Arrow (開始列在左邊)
    參考資料:

    透過 getenv 與 getProperties 取得系統環境變數與JVM屬性設定

          在 Java 中我們可以透過 System.getProperties() 取得 JVM 參數設定System.getenv() 來取得作業系統的環境變數設定。你可以在 The Java Tutorials 裡面參考 System Properties 與 Environment Variables 教學文章看到其他用法。

         如果你使用 Eclipse 你可以透過 -D<Key>=<Value> 的方式在 Run > Run Configurations... > (x)= Arguments > VM Arguments 來設定額外的 JVM 屬性設定。例如你可以填入 -DColor=blue 來設定 Color 屬性為 blue。如下圖所示:


    簡易的範例程式如下:
        // 列出目前所有的 JVM 屬性設定
        System.getProperties().list(System.out); 
        
        // 透過 getProperty 單獨取出特定的某個屬性設定值    
        System.out.println("Color = " + System.getProperty("file.separator"));    
    
        // 取出我們設定的屬性值,注意屬性名稱是 case sensitive
        // 如果你寫成 color 得到的會是 null
        System.out.println("Color = " + System.getProperty("Color"));
    
        // 你也可以使用下列方式,當所指定的屬性沒有鍵值時,回傳你所設定的預設值
        // 下面的範例當沒有設定 Color 屬性鍵值時會回傳預設的 Pink 值
        System.out.println("Color = " + System.getProperty("Color", "Pink")); 
    
        // 列出目前作業系統所有的環境變數設定
        Set<Map.Entry<String, String>> envSet = System.getenv().entrySet();
        for (Map.Entry<String, String> set: envSet) {
            System.out.println(set.getKey() + " = " + set.getValue());
        }
        // 透過 System.getenv(key) 的方式單獨取出你想要的屬性設定
        System.out.println("SystemDrive = " + System.getenv("SystemDrive"));
        System.out.println("TEMP = " + System.getenv("TEMP"));
    


    參考文章:



    2013年11月13日 星期三

    保護回傳參考型態的物件

          今天在 "最新 Java 7 程式語言 施威銘" 這本書中看到了一篇內容,大概的內容是講述當我有一個類別 Circle, 該類別裡面包含了另一個類別 Point 物件紀錄 Circle 的中心點,為了保護 Point 物件,所以在 Circle 裡面使用 private 來修飾 Point 物件;但當外部需要取得中心點資料時,便在 Circle 類別寫了一個傳回 Point 的參考物件 method,此時因為外部可以取得 Point 的物件參考,所以外部就可透過 所得到的 Point 物件參考來設定修改資料,這樣就違背了當初我們不想讓外部的使用者來隨便設定 Circle 的中心點的用意,也失去了把 Point 設成 private 作用。
         所以為了避免這種情況發生,可以使用下列方式:
    1. new 一個新的 Point 物件,拷貝目前 Circle 物件內的 Point 物件資料。
    2. 將 Point 變成 immutable 的類別,也就是不提供設定(setXX ) method。
    3. Point 類別 implements Cloneable 類別,然後回傳 clone 物件。
        書本使用第一個方式,在回傳 Point 物件參考的 method 中,可以先用 new 的方式將目前在 Circle 類別內的 Point 物件拷貝一份,然後傳回去。這樣外部修改 Point 物件時就不會影響原本的 Circle 物件裡 Point 物件資料了。

    範例程式:

    class Point implements Cloneable {
        private int x;
        private int y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
        // 2. 把 setPoint 移除,讓 Point 變成 immutable 的類別
        public void setPoint(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public int getX() {
            return x;
        }
        public int getY() {
            return y;
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    class Circle {
        private Point point;
        private int radius;
        public Circle(int x, int y, int r) {
            point = new Point(x, y);
            radius = r;
        }
        public Point getPoint() {
            return point;
        }
        public Point getReadOnlyPoint() {
            try {
                // 3. 讓 Point 類別實作 Cloneable,然後回傳 clone 物件 
                return (Point)point.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
        public Point getReadOnlyPoint2() {
            //1. 使用 new 的方式,將目前的Point 資料拷貝一份
            return new Point(point.getX(), point.getY());
        }
        
        @Override
        public String toString() {
            return String.format("(%d, %d) ,radius = %d", point.getX(), point.getY(), radius);
        }
    }
    
    public class ProtectReferenceObj {
        public static void main(String[] args) {
            Circle circle = new Circle(1,1,2);
            Point pt = circle.getPoint();
            System.out.println("Before: " + circle);
            pt.setPoint(10, 20);
            System.out.println("After: " + circle);
            System.out.println("================================");
            System.out.println("Before: " + circle);
            Point pt2 = circle.getReadOnlyPoint();
            pt2.setPoint(11, 22);
            System.out.println("After: " + circle);
            System.out.println("pt2.x =  " + pt2.getX() + " pt2.y = " + pt2.getY());
            System.out.println("================================");
            System.out.println("Before: " + circle);
            Point pt3 = circle.getReadOnlyPoint2();
            pt3.setPoint(55, 99);
            System.out.println("After: " + circle);
            System.out.println("pt3.x =  " + pt3.getX() + " pt3.y = " + pt3.getY());
        }
    }
    


    輸出結果:
    Before: (1, 1) ,radius = 2
    After: (10, 20) ,radius = 2
    ================================
    Before: (10, 20) ,radius = 2
    After: (10, 20) ,radius = 2
    pt2.x =  11 pt2.y = 22
    ================================
    Before: (10, 20) ,radius = 2
    After: (10, 20) ,radius = 2
    pt3.x =  55 pt3.y = 99
    


    2013年11月5日 星期二

    ArrayList 使用 toarray 轉換成物件陣列

         在某些情況下,我們希望能夠將 ArrayList 物件所存的內容轉換成陣列的形式,在 ArrayList 中提供了 toarray 方法來達到我們的需求。下面是 Java 所提供的 toarray 方法的原始碼:

        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }
    
        public T[] toArray(T[] a) {
            if (a.length < size)
                // Make a new array of a's runtime type, but my contents:
                return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            System.arraycopy(elementData, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }
    
    
         有上面可知,我們有兩個方式可以使用 toarray 方法,一個是不帶任何參數 toarray 方法回傳 Object 陣列,另外一個是回傳你所傳入的型態陣列。
         我們先來看 public T[] toArray(T[] a) 的方法,從原始碼中,我們發現此方法會使用參數的 length 的屬性,代表該參數必須要先配置過記憶體才行,如果直接傳 null 給它會引發 "java.lang.NullPointerException" 的例外事件。再回頭看一下原始碼,會發現當你所配置的陣列元素小於目前 ArrayList 所儲存的元素時,toarray 方法會幫你配置足夠的元素來儲存目前 ArrayList 物件中所含的所有元素。而當你的所配置的陣列元素個數大於目前會將你所配置的第 size 元素設定為null。基本上你可以想成超出的元素都會被設置成 null 就可以。(PS: 要使用 ArrayList 其型態一定是參考型態,如果使用基本型態會出現編譯失敗 ,而物件陣列的預設值為 null)。

        另外一個 toArray法是回傳 Object 陣列,由於兩個陣列基底型別不同時,不能互相參照,所以你無法直接將回傳的 Object 陣列轉成你要的型態陣列。但是你可以針對每個 Object 元素做轉型。

    範例程式如下:

         static void toArrayDemo() {
            
            ArrayList<integer> list = new ArrayList<integer>(){{
                add(1);
                add(2);
                add(3);
                add(4);
            }};
    
            //"main" java.lang.NullPointerException
            //Integer[] test = null; 
            //test = list.toArray(test); 
            // or Integer[] test = list.toArray(null);
            
            // 配置的元素小於 ArrayList 所存的元素各數少時,
            // toArray 會幫你重新配置足夠的陣列個數來儲存。
            Integer[] test = list.toArray(new Integer[0]);
            System.out.print("<1>[ ");
            for (Integer val : test) {
                System.out.print(val + " ");
            }
            System.out.println("]");
            // 配置大於 ArrayList 所存的 元素個數,多餘的陣列元素都是 null
            Integer[] test2 = list.toArray(new Integer[10]);
            System.out.print("<2>[ ");
            for (Integer val : test2) {
                System.out.print(val + " ");
            }
            
            System.out.println("]");
            
            // 配置符合目前 ArrayList 所含的元素個數
            Integer[] test3 = list.toArray(new Integer[list.size()]);
            System.out.print("<3>[ ");
            for (Integer val : test3) {
                System.out.print(val + " ");
            }
            System.out.println("]");
            
            //無法將 Object 陣列轉成其他型態的陣列
            //[Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
            //Integer[] test4 = (Integer[] )list.toArray();
            
            Object [] obj = list.toArray();
            
            System.out.print("<4>[ ");
            for (Object val : obj) {
                // 你可以對每一個 Object 中的元素轉型成 Integer 型態的物件
                // 因為我們宣告的 ArrayList 是儲存 Integer 物件,所以每一個
                // Object 物件都是參考到  Integer 物件
                
                System.out.print( ((Integer)val).intValue() + " ");
                // 下面方式與上面轉型所列印出來的結果相同,因為每一個 Object 元素
                // 都是參考到 Integer 物件,而 Integer 的 toString method 就是列印其值。
                //System.out.print( val + " ");
            }
            System.out.println("]");
        }
    

    輸出結果:
    <1>[ 1 2 3 4 ]
    <2>[ 1 2 3 4 null null null null null null ]
    <3>[ 1 2 3 4 ]
    <4>[ 1 2 3 4 ]

    補充:
        Object[] obj = new Object[size] 與 Object[] intObj = new Integer[2]  的不同是,obj 陣列可以指定
    任何型態的物件參考,每一個元素值不一定要儲存相同的物件。而 intObj 是參考到 Integer 陣列所以其元素只能儲存 Integer 物件,儲存其他型態物件會引發 "java.lang.ArrayStoreException" 例外事件。另外 intObj 是參考到 Integer 陣列,所以你可以將 intObj 指定給其他 Integer 陣列來參考。

    範例程式如下:

        static void arrayDemo() {
            Object [] intobj = new Integer[2];
            System.out.println("obj instance Integer[] = " + (intobj instanceof Integer[]));
            obj[0] = new Integer(10);
            //Exception in thread "main" java.lang.ArrayStoreException: java.lang.Float
            //obj[1] = new Float(10.f);
            
            Object [] obj2 = new Object[2];
            System.out.println("obj2 instance Integer[] = " + (obj2 instanceof Integer[]));
            obj2[0] = new Integer(10);
            obj2[1] = new Float(10.f);
            System.out.println("obj2[0] = " + obj2[0] + " , obj2[1] = " + obj2[1]);
        }