養成良好的編程習慣,提高代碼質量

“不積跬步,無以至千里,不積小流,無以成江海”,程序員如何提高代碼質量?我們不僅要知其然,還要知其所以然,我們要從點點滴滴的積累開始的。這篇帖子裏記錄了編程時的應該注意的一些細節,如有需要後續還會補充,希望通過不斷的積累,提高編程質量。

可序列化接口Serializable

類實現Serializable接口的目的是爲了可持久化,比如網絡傳輸或本地存儲,爲系統的分佈或異步部署提供先決支持條件。若沒有序列化,現在我們熟悉的遠程調用,對象數據庫都不可能存在。

    序列化和反序列化是對應的,以下用代碼描述實現了序列化接口Serializable的類在磁盤上的存儲過程及反序列化,其在網絡上的傳輸道理也是一樣的。

package org.iti.wxl.serializable;  
  
import java.io.Serializable;  
  
/** 
 * 實現了Serializable的實體類 
 * 
 */  
public class Person implements Serializable{  
      
    private static final long serialVersionUID = 6388172609871883630L;  
    private String name;  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
}  
爲模擬序列化的過程我們創建序列化工具類,如下:
package org.iti.wxl.serializable;  
  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectInput;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.io.Serializable;  
  
public class SerializableUtils {  
    private static String FILE_NAME="e:/obj.bin";  
    //序列化數據保存到磁盤  
    public static void writeObject(Serializable s){  
        try {  
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_NAME));  
            oos.writeObject(s);  
            oos.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
  
    //反序列化從磁盤讀取數據  
    public static Object readObject(){  
        Object obj = null;  
        try {  
            ObjectInput input = new ObjectInputStream(new FileInputStream(FILE_NAME));  
            obj = input.readObject();  
            input.close();  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        return obj;  
    }  
} 

序列化保存數據到磁盤上
package org.iti.wxl.serializable;  
public class Producer {  
    public static void main(String[] args) {  
        Person p = new Person();  
        p.setName("小明");  
        // 序列化保存到磁盤上  
        SerializableUtils.writeObject(p);  
    }  
}  

反序列化,從磁盤讀取數據:
package org.iti.wxl.serializable;  
  
public class Consumer {  
    public static void main(String[] args) {  
        //反序列化  
        Person p =(Person)SerializableUtils.readObject();  
        System.out.println(p.getName());  
    }  
} 

在反序列化時,若類的版本號serialVersionUID不一致,反序列化時會報一個InvalidClassexception異常,另外在反序列化時,類中的構造函數不會執行。

奇偶校驗用偶校驗,避免使用奇校驗

JDK提供的奇偶校驗代碼模擬如下:

public class Remainder {  
       //dividend被除數,divisor除數  
    public static int remainder(int dividend, int divisor) {  
        return dividend - dividend/divisor*divisor;  
    }  
} 

 當使用取模運算“%”做奇偶校驗時,JDK會依照以上公式進行運算,此時dividend爲要校驗的數,divisor=2我們發現當被除數爲負數且爲奇數時,餘數爲-1,如果我們的奇偶校驗公式爲i%2 =1 ? "奇數":"偶數";那麼當i爲負奇數時結果判斷會錯誤,因此我們做奇偶校驗時要用偶校驗,即:i%2 == 0 ? "偶數":"奇數";

java中的引用問題

java中沒有指針的概念,但我們要理解另一個名詞“引用”。看下面的例子:

實體類

public class IntString {  
    private Integer no;  
    private String str;  
    public Integer getNo() {  
        return no;  
    }  
    public void setNo(Integer no) {  
        this.no = no;  
    }  
    public String getStr() {  
        return str;  
    }  
    public void setStr(String str) {  
        this.str = str;  
    }  
    @Override  
    public String toString() {  
        return "IntString [" + (no != null ? "no=" + no + ", " : "")  
                + (str != null ? "str=" + str : "") + "]";  
    }  
}  

測試類:
public class Test {  
    public static void main(String[] args) {  
        List<IntString> test = new ArrayList<IntString>();  
        IntString is1 = new IntString();  
        is1.setNo(1);  
        is1.setStr("一");  
        IntString is2 = new IntString();  
        is2.setNo(2);  
        is2.setStr("二");  
        IntString is3 = new IntString();  
        is3.setNo(3);  
        is3.setStr("三");  
        test.add(is1);  
        test.add(is2);  
        test.add(is3);  
        List<IntString> newtest = new ArrayList<IntString>();  
        newtest = test;  
//      List<IntString> newtest = test;  
        System.out.println("前" + newtest);  
        test.get(0).setStr("1");  
        System.out.println("後" + newtest);  
    }  
} 

輸出結果:
前[IntString [no=1, str=一], IntString [no=2, str=二], IntString [no=3, str=三]]  
後[IntString [no=1, str=1], IntString [no=2, str=二], IntString [no=3, str=三]]

程序中改變了test實體裏的一個對象的某個參數的值,但是打印出newTest後發現它的內部對象值發生了變化,解釋如下:newtest = test時,newTest和test兩個名字雖然不一樣,但是都指向同一塊內存地址,test發生變化也就是newTest發生了變化。

java中基本類型可以分爲三類,字符類型char,布爾類型boolean以及數值類型byte、short、int、long、float、double,對於非基本類型的對象類數據都是採用引用的方式來處理,那麼在做賦值操作“=”時,是引用的賦值,兩個不用名稱的應用指向同一個地址,其中一個數值發生變化兩個就都發生變化了。

另外,對於基本類型,JVM提供常量池,用到某數值的時從常量池裏取值,這個時候用==判斷是否相等,數值相等時一定相等,“==”判斷的是地址相等。而對於非基本類型數值相等也不一定“==”,因此我們應該用equals方法來判斷值相等,而對於在內存中只存在一份的判斷可以用“==”例如字節碼等。



發佈了1 篇原創文章 · 獲贊 21 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章