2008年10月14日 星期二

static 的使用時機

首先大致了解一下 static 這個修飾字,及使用規則。

static 是屬於類別層級的修飾字,在記憶體裡面只存有一份,不論我們 new 了幾個物件,該成員或函示始終指向同一個記憶體位置。而 static 成員只能被 static 成員呼叫或存取。

在使用的時機方面,static 是在任何物件運作之前就會被呼叫的,因此我們也常常使用
main method 來作測試,再來就是常見的公用 method,類似 Utilites,與不會改變的常數等等。

下列有個例子舉的很好,可以拿來說明:

public class StaticModifier
{
int counter1 = 0;
static int counter2 = 0;

public void Increase(String s)
{
counter1++;
counter2++;
System.out.print(s + "'s counter1 = " + counter1);
System.out.println("; counter2(static) = " + counter2);
}

public static void main(String argv[])
{
StaticModifier sta1 = new StaticModifier();
StaticModifier sta2 = new StaticModifier();

sta1.Increase("sta1");
sta1.Increase("sta1");
sta2.Increase("sta2");
}
}
程式輸出為:
sta1's counter1 = 1; counter2(static) = 1
sta1's counter1 = 2; counter2(static) = 2
sta2's counter1 = 1; counter2(static) = 3
Reference:
http://www.javaworld.com.tw/jute/

2008年10月12日 星期日

Override equals(), override hashCode()

這項規則可以參考 java.lang.Object 的規格書

1. 在同一個應用程式執行期間, 對同一個物件呼叫 hashCode(), 必須回傳相同的整數結果
2. 如果兩個物件被 equals(Object) 視為相等, 則這兩個物件呼叫 hashCode() 必須獲得相同的整數結果
3. 如果兩個物件被 equals(Object) 視為不相等, 則這兩個物件呼叫 hashCode() 不必獲得相同的整數結果

若要方便產生這些原始碼,也可以參閱 commons.lang.builder
org.apache.commons.lang.builder

另外我們可以研究一下 java.lang.Object, java.lang.String 底下的原始碼
java.lang.Object

public boolean equals(Object obj) {
return (this == obj);
}
java.lang.String
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
很明顯的,equals()在比較是否 reference 到同一個記憶體位置,若為 String 物件,則比對物件的內容。

2008年10月7日 星期二

利用 JAD 將程式碼反組譯心得

最近有一項 task 還蠻有趣的,由於 Production 上的 JAR 檔案與版本控制上的程式碼不盡相同,因此每次改程式的方式,都是從測試機將 JAR 檔抓下來再將修好的 .class 檔案放進去測試,但這樣比較有風險,因為我們不知道放進去的程式會不會影響到其它的 binary 檔案。

為了作調整,將 Production 與 SVN 裡面的程式碼作同步是勢在必行了,但是 binary 檔案與 java 的格式本來就不同,那要如何作比較? 這裡提供一個簡單的方法,利用 jad.exe 將我們從 SVN checkout 的檔案反組譯,這樣他跟 JAR 檔就有比較的基準了。

每次 build 的檔案是從版本控制上下來的程式碼,比較容易追朔、也降低了風險,最重要的是我們可以確定測試機、與正式機的內容是一樣的。

2008年10月2日 星期四

開發產品軟體雜感

由於在軟體界已逾四年,碰過比較有印象的產品有ATG(電子商務平台),跟目前要開發的產品Firewire CMS(內容管理系統)。ATG是一個滿成熟的平台,在四五年前,就已經有controller-->manager-->類似hibernate OR mapping 的觀念,並擁有自己的 taglib,也就是整套都在他自己的環境下被封裝好了,需要照著產品自訂的流程跟API來作開發。

最近碰的這套是內容管理系統,以開發的角度來說是較容易些。因為他的 development guide 只定義了自己的API跟 taglib,除了要懂這些標籤跟少數的API,其實就沒有什麼太多技術面的問題,剩下的都是比較屬於如何利用他自己的流程、介面來管理內容。

而台灣自製的軟體產品我大概碰過兩套,都是跟知識管理有關係的,其中一套設計的比較好、利用struts,EJB來建構,裡面也有很多的design pattern可以參考跟學習,當然如果不作分散式的處理,使用EJB實在有點大材小用,也增加開發的額外負擔。

當我們的專案碰到產品時,應該不能以寫程式的角度來看,不然我們可能會認為,這些功能我用struts, spring 都作的出來,為什麼要增加額外的負擔再去學這些流程。而這些流程跟技術,都有一定的道理存在。

例如 CMS 強調的就是產品上稿,與產品之間的關連性,只要將這些element與關連建起來,利用他自製的tag,就可以很容易的將這些功能表現出來。

雖然我們能夠在這既有的 framework 上發揮的點並不多,但是這些產品畢竟都還是 java-based的,可以從開發的流程去檢討、可以試著整進CI、作適度的 refactoring,都可以有助於專案的品質。

2008年9月22日 星期一

java 的記憶體配置

了解 java 記憶體的配置,有助於程式撰寫的 performance tuning

首先以變數的角度來說明:
1. heap variable:
class variable(method 之外並加上 static 的修飾字)、instance variable、array component。
這類變數會自動被 JVM 初始化成預設值。

2. stack variable:
通稱廣義的區域變數,其佔用的記憶體在 stack 中,這類變數包括了狹義的區域變數(宣告在 method 內的變數)、
method parameter、exception-handler parameter、constructor parameter。此類變數會被 JVM 初始化成傳入值。
而狹義的區域變數不會被 JVM 初始化成預設值,使用者必須自行初始化該變數。

下列是以記憶體的配置來探討:
1. heap (dynamic memory allocate):
是動態配置記憶體空間,且可以隨時配置,由JVM負責。
只要是用new 產生的oject都是存放在heap中,且通常用一個存放在stack的reference 來指向這個oject
compiler 不會知道這個從heap中獲得多少空間,也不會知道其配置到的空間會存放多久。

2. stack (stack allocation):
其 Life cycle 會受到block scope的影響,當進入block時,會自動配置記憶體空間,離開這個SCOPE時,其記憶體配置就會隨之消失。
可以將object的reference 儲存於stack內。

Reference:
http://www.oreilly.com.tw/column_sleepless.php?id=j015
http://www.javaworld.com.tw/jute/

2007年12月18日 星期二

Creational 模式學習心得

Factory method: 適用於多型化的操作,利用一個 factory method,將封裝物件的行為,並將每個物件都對應於一個 factory class。

Builder: 適用於多型化的操作,builder method 用來組合物件的行為。

Prototype: 主要用來複製物件。

Singleton: 適用於只需要一份 instance 時(只能 new 出一份 instance)。

使用 Pattern除了能夠封裝細節,還能使程式更佳彈性。

2007年11月20日 星期二

PostgreSQL Hibernate 連線設定

以下的連線設定以 hibernate 3.0 以上版本為基礎, 除了基本的 hibernate 程式庫, 您還需要下載 PostgreSQL Driver, 才能順利執行.
由於 PostgreSQL 的資料型態與一般的 DB 略為不同, 建議在測試專案時可以將 "hbm2ddl.auto" 這個屬性設為 "true", 讓 hibernate 自動去對應最合適的資料型別, 並自動建立索引, sequence 等服務.

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5432/postgres</property>
<property name="connection.username">inqgen</property>
<property name="connection.password">inqgen</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<mapping resource="inqgen/Person.hbm.xml"/>

</session-factory>

</hibernate-configuration>