星期一, 1月 04, 2010

Keystoke causes android.process.acore to crash

After replacing the touchscreen device with a LCD and keyboard, I find android.process.acore will crash while trying to type with the keyboard. This bug also occurs when executing Contacts and dialer applications. According to the messages shown by logcat, this bug is resulted from failing to load resource required by Android.

android.process.acore_crash

According to this description, Android system cannot find the required resources for notouch device. So, we can fix this bug by copying each folder ending with -finger to the one ending with -notouch.

D/AndroidRuntime(  760): Shutting down VM
W/dalvikvm(  760): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
E/AndroidRuntime(  760): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime(  760): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.contacts/com.android.contacts.DialtactsActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x7f030005
E/AndroidRuntime(  760):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2268)
E/AndroidRuntime(  760):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
E/AndroidRuntime(  760):        at android.app.ActivityThread.access$1800(ActivityThread.java:112)
E/AndroidRuntime(  760):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
E/AndroidRuntime(  760):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(  760):        at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime(  760):        at android.app.ActivityThread.main(ActivityThread.java:3948)
E/AndroidRuntime(  760):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(  760):        at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime(  760):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
E/AndroidRuntime(  760):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
E/AndroidRuntime(  760):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(  760): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7f030005
E/AndroidRuntime(  760):        at android.content.res.Resources.getValue(Resources.java:846)
E/AndroidRuntime(  760):        at android.content.res.Resources.loadXmlResourceParser(Resources.java:1796)
E/AndroidRuntime(  760):        at android.content.res.Resources.getLayout(Resources.java:685)
E/AndroidRuntime(  760):        at android.view.LayoutInflater.inflate(LayoutInflater.java:318)
E/AndroidRuntime(  760):        at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
E/AndroidRuntime(  760):        at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:309)
E/AndroidRuntime(  760):        at android.app.Activity.setContentView(Activity.java:1626)
E/AndroidRuntime(  760):        at com.android.contacts.DialtactsActivity.onCreate(DialtactsActivity.java:73)
E/AndroidRuntime(  760):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime(  760):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
E/AndroidRuntime(  760):        ... 11 more
I/Process (  556): Sending signal. PID: 760 SIG: 3
I/dalvikvm(  760): threadid=7: reacting to signal 3

References:
http://d.android.com/guide/topics/resources/index.html

Error in loading /system/usr/keychars/qwerty.kcm.bin

While typing on the keyboard, the home screen disappears shortly and logcat shows the following error messages:

This bug is resulted from failing to read /system/usr/keychars/qwerty.kcm.bin for wrong access permission. It can be fixed by adding the read access permission to this file by

chmod 644 /system/usr/keychars/qwerty.kcm.bin

E/KeyCharacterMap( 633): Can't find any keycharmaps (also tried /system/usr/keychars/qwerty.kcm.bin)
I/DEBUG ( 510): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 510): Build fingerprint: 'generic/generic/generic/:1.5/CUPCAKE/eng.jack_zhuang.20091119.140022:eng/test-keys'
I/DEBUG ( 510): pid: 633, tid: 633 >>> android.process.acore <<<
I/DEBUG ( 510): signal 11 (SIGSEGV), fault addr 00000000
I/DEBUG ( 510): r0 0000a9d0 r1 4001b588 r2 00000000 r3 41049c54
I/DEBUG ( 510): r4 be812550 r5 00000004 r6 ad32ea71 r7 41049c30
I/DEBUG ( 510): r8 be812530 r9 41049c28 10 41049c18 fp 00000000
I/DEBUG ( 510): ip ad32ea71 sp be812530 lr ad00e3b8 pc ad32ea70 cpsr a0000030
I/DEBUG ( 510): #00 pc 0002ea70 /system/lib/libandroid_runtime.so
I/DEBUG ( 510): #01 lr ad00e3b8 /system/lib/libdvm.so
I/DEBUG ( 510): stack:
I/DEBUG ( 510): be8124f0 00000001
I/DEBUG ( 510): be8124f4 41f84710 /data/dalvik-cache/system@framework@framework.jar@classes.dex
I/DEBUG ( 510): be8124f8 00000001
I/DEBUG ( 510): be8124fc ad048977 /system/lib/libdvm.so
I/DEBUG ( 510): be812500 00000328
I/DEBUG ( 510): be812504 4108a368 /dev/ashmem/dalvik-LinearAlloc (deleted)
I/DEBUG ( 510): be812508 be812560 [stack]
I/DEBUG ( 510): be81250c 0000000a
I/DEBUG ( 510): be812510 0000000f
I/DEBUG ( 510): be812514 ad063ba3 /system/lib/libdvm.so
I/DEBUG ( 510): be812518 00000004
I/DEBUG ( 510): be81251c ad05a705 /system/lib/libdvm.so
I/DEBUG ( 510): be812520 00000018
I/DEBUG ( 510): be812524 4108a368 /dev/ashmem/dalvik-LinearAlloc (deleted)
I/DEBUG ( 510): be812528 df002777
I/DEBUG ( 510): be81252c e3a070ad
I/DEBUG ( 510): #00 be812530 4108a368 /dev/ashmem/dalvik-LinearAlloc (deleted)
I/DEBUG ( 510): be812534 0000bc60 [heap]
I/DEBUG ( 510): be812538 ad32ea71 /system/lib/libandroid_runtime.so
I/DEBUG ( 510): be81253c 4001b588 /dev/ashmem/mspace/dalvik-heap/zygote/0 (deleted)
I/DEBUG ( 510): be812540 00001071
I/DEBUG ( 510): be812544 0000bc60 [heap]
I/DEBUG ( 510): be812548 be812550 [stack]
I/DEBUG ( 510): be81254c ad040a8d /system/lib/libdvm.so
I/DEBUG ( 510): be812550 41049c28
I/DEBUG ( 510): be812554 41fb2789 /data/dalvik-cache/system@framework@framework.jar@classes.dex
I/DEBUG ( 510): be812558 ad32ea71 /system/lib/libandroid_runtime.so
I/DEBUG ( 510): be81255c be8125c8 [stack]
I/DEBUG ( 510): be812560 be8125c8 [stack]
I/DEBUG ( 510): be812564 00000001
I/DEBUG ( 510): be812568 ad00e540 /system/lib/libdvm.so
I/DEBUG ( 510): be81256c 41ea7bdc /data/dalvik-cache/system@framework@framework.jar@classes.dex
I/DEBUG ( 510): be812570 41049c3c
I/DEBUG ( 510): be812574 be8125c0 [stack]
D/Zygote ( 512): Process 633 terminated by signal (11)

星期二, 9月 01, 2009

指定Java Application使用的語言

開發Java程式時, 可以利用resource的方式, 將程式的訊息以及ui等設計成支援多國語言, 然後執行時加上-Duser.language=locale_name或-Duser.country=country_name就可以切換不同的語言介面.

完整的指令為

顯示英文介面:
java -Duser.language=en -jar test.jar或
java -Duser.country=us -jar test.jar

顯示中文介面:
java -Duser.language=zh -jar test.jar或
java -Duser.country=TW -jar test.jar

星期日, 8月 23, 2009

在Linux中檢視目前cpu的運作頻率

在Windows系統中我們可以很輕易地檢視目前cpu的運作頻率, 在Linux上也是可以輕易做到的. 只要執行下面的指令:

$ cat /proc/cpuinfo

不僅可以在cpu MHz看到目前的運作頻率, 還可以看到許多其他cpu的資訊.
如果不想看到那麼多雜七雜八的資訊, 可以搭配grep將所要檢查的資訊過慮出來, 例如:

$ grep -E 'GHz|MHz' /proc/cpuinfo

這樣就只會顯示cpu的最高工作頻率以及目前的工作頻率而已.

星期四, 8月 20, 2009

解決Tab mix plus與google toolbar最常造訪的網站功能相衝

Google toolbar有一個功能, 就是在開啟新分頁時會顯示最常造訪的網站清單. 可是這個功能在安裝了Tab mix plus附加元件之後, 就會被廢了武功, 完全跑不出來. 後來在網路上找到了解決辦法, 方法很簡單, 只要將chrome://google-toolbar/content/new-tab.html如下圖所示, 加到Tab mix plus選項->分頁->開啟分頁->新增分頁時自動載入設定中即可.


星期三, 8月 19, 2009

系統自動掛載ntfs partition

ntfs-3g所賜, 我們已經可以在Linux上掛載ntfs的檔案系統, 進行資料的讀寫動作. 雖然Linux系統UI已經做得很好, 只要用滑鼠點一下ntfs partition就會自動幫我們掛載到系統上, 可是總覺得如果可以如其他的ext3 partition一樣, 在開機後就自動掛載那不是更完美嗎? 既然有這個想法, 就要想辦法解決一下. 其實很簡單, 還是一樣利用/etc/fstab就可以輕鬆達到.

首先, 找出ntfs partition的UUID, 方法可以參考取得partition的UUID
再來就是編輯/etc/fstab這個檔案, 在檔案中加上
UUID=ntfs_partition_uuid mount_point ntfs-3g defaults 0 2
這樣就可以了.

例如: 我們的ntfs partition的uuid如果是4C54A5A254A58EF0, 並且要將該partition掛載到/media/VAIO目錄中
$ sudo mkdir /media/VAIO
$ sudo echo "UUID=4C54A5A254A58EF0 /media/VAIO ntfs-3g defaults 0 2" >> /etc/fstab
$ sudo mount -a

取得partition的uuid

現在Linux掛載partition常常使用UUID的方式來指定所要掛載的partition, 要取得partition的UUID有以下幾個方法:

1. 最簡單的方式是直接執行blkid, 會列出目前連接到系統上所有磁碟的partition UUID, 檔案系統以及label, 例如:
$ blkid
/dev/loop0: TYPE="squashfs"
/dev/sda1: UUID="4C54A5A254A58EF0" LABEL="VAIO" TYPE="ntfs"
/dev/sda5: UUID="4CFCC181FCC165B4" TYPE="ntfs"
/dev/sda6: UUID="a5050769-1c80-4e7c-8b7c-da810624d910" TYPE="ext3"
/dev/sda7: UUID="8c28803c-3390-46d7-bb90-fd9a83c0bff3" TYPE="swap"
/dev/sda8: UUID="95206ddf-7ffd-4ddb-8ced-631b5df70b26" TYPE="ext3"

2. 另外也可以執行sudo vol_id 也可以得到指定partition的相關資訊, 例如:
$ sudo vol_id /dev/sda1
ID_FS_USAGE=filesystem
ID_FS_TYPE=ntfs
ID_FS_VERSION=3.1
ID_FS_UUID=4CFCC181FCC165B4
ID_FS_UUID_ENC=4CFCC181FCC165B4
ID_FS_LABEL=
ID_FS_LABEL_ENC=

星期日, 8月 09, 2009

struct成員的記憶體位址alignmentt

一般來說, compiler編譯c程式時, 遇到struct時會對成員資料的位址進行alignment的動作, 以增加記憶體讀取的效率. 所以struct往往會佔有比所有資料成員大小和還要多的記憶體空間. 例如下列的struct data的記憶體大小為12.
struct data {
char num;
int size;
void *ptr;
};

如果因為特殊需要, 需要節省記憶體, 則可以在程式碼中需要進行pack memory的struct前後, 採用#pragma pack來告訴compiler是否要進行pack memory的動作, 例如下列的struct packed_data的記憶體大小則為9, 不是12.
#pragma pack(1)
struct packed_data {
char num;
int size;
void *ptr;
};
#pragma pack()

讓evince顯示中文

Ubuntu預設安裝的evince雖然可以讀取pdf檔案, 可是如果檔案內容包含中文的話, 中文字就會無法正常地顯示出來. 雖然Adobe PDF reader也很好用, 而且又是免費軟體, 但是總是有些缺點, 例如: 開啟速度較慢, 不是open source...

要解決evince無法顯示中文的問題, 只要安裝poppler-data套件後就解決囉.

星期六, 8月 08, 2009

修正VMware on Ubuntu 9.04無法使用方向鍵的問題


如果在Ubuntu 9.04中安裝VMware, 並且在VMWare發生方向鍵無法使用的情形, 只要在/etc/vmware/config檔案中加入
xkeymap.nokeycodeMap = true

VMware的虛擬機器啟動時會出現如下圖所示的提示訊息, 不用理會沒關係.



資料來源:
  • http://communities.vmware.com/message/1087494#1087494

星期六, 7月 25, 2009

切換ubuntu的預設輸入法

im-switch -s gin
用gcin當作預設輸入法

im-switch -s scim
用scim作為預設輸入法

星期三, 7月 22, 2009

用gstreamer下載mms檔案

gst-launch mmssrc location=mms://air.hihit.net/studio/090722baa.wma ! filesink location=test.wma

gstreamer真是個好東西阿

如果執行時出現ERROR: pipeline could not be constructed: no element "mmssrc", 那是因為預設mmssrc並沒有安裝mms相關的plugin, mmssrc在Gstreamer Bad Plugins中, 所以只要將它安裝起來就可以了. 安裝方式如下:

sudo apt-get install gstreamer0.10-plugins-bad

星期一, 5月 18, 2009

建立Android XML file

如果使用File->New->Android XML File會出現下列錯誤的話,

則可以改按工具列上的按鈕來建立,如下圖滑鼠指標停放處所示。

星期二, 3月 17, 2009

Windows Service學習心得

Windows service與一般Windows的應用程式一樣, 也是一個執行檔. 不同的是, Windows service程式是以console application的形式在系統背景中執行. 既然Windows service是以console application的形式存在, 所以在撰寫Windows service時, source code中第一個最重要的地方就是main(), 也是整個service program的進入點.

在main中, 我們必須完成的事情很簡單, 就是將每個service的名稱以及其對應的serivce procedure註冊就好了. 方法很簡單, 就是先將SERVICE_TABLE_ENTRY的內容填好, 然後呼叫StartServiceCtrlDispatcher()就可以了.

#include <windows.h>
#include <stdio.h>

#define SLEEP_TIME 5000
#define LOGFILE "c:\\Temp\\memstatus.txt"

int WriteToLog(char* str)
{
    FILE* log;
    log = fopen(LOGFILE, "a+");
    if(log == NULL)
        return -1;
    fprintf(log, "%s\n", str);
    fclose(log);
    return 0;
}

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();

void main()
{
    SERVICE_TABLE_ENTRY ServiceTable[2];

    ServiceTable[0].lpServiceName = "MemoryStatus";
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    ServiceTable[1].lpServiceName = NULL;    // 最後一個service entry table欄位必須為NULL
    ServiceTable[1].lpServiceProc = NULL;

    // Start the control dispatcher thread for our service
    StartServiceCtrlDispatcher(ServiceTable);
}

有幾點必須要說明一下, 首先, 一個service program不一定只能包含一種service, 如果有多個service, 則上列的ServiceTable陣列的element則會有多個. 只要記住最後一個element的service name和service procedure都必須為NULL表示陣列結束就可以了. 如此一來, service program就是負責作為SCM (Service Configuration Manager)與service之間溝通的橋樑, 也就是所謂的control dispatcher, 負責將SCM傳送過來的request傳遞給相對應的service, 並且監控service的執行.

另外, SCM啟動service program後, 必須在30秒內呼叫StartServiceCtrlDispatcher(), 否則會回報為啟動錯誤. 所以如果每個service的啟動有一些啟動程序必須執行, 應該寫在service procedure中, 也就是上例中的ServiceMain.

ServiceMain是service的entry point, 也就是我們在service program中為每個service所註冊的service procedure. 每個service的service procedure會由dispatcher產生一個新的thread來執行. 在service procedure中我們首先必須盡快為service註冊control handler, 也就是呼叫RegisterServiceCtrlHandler()來註冊該service名稱所對應的service control handler. 不管service的狀態是否有改變, 在control handler中都要回報service status, 透過呼叫SetServiceStatus()回報service status給SCM.

void ServiceMain(int argc, char** argv)
{
    int error; 

    
    hStatus = RegisterServiceCtrlHandler("MemoryStatus", (LPHANDLER_FUNCTION)ControlHandler);
    if(hStatus == (SERVICE_STATUS_HANDLE)0)
    {
        // Registering Control Handler failed
        return;
    }
   
    ServiceStatus.dwServiceType = SERVICE_WIN32;
    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint = 0;
    ServiceStatus.dwWaitHint = 0;
    SetServiceStatus(hStatus, &ServiceStatus);

    // Initialize Service
    error = InitService();
    if(error)
    {
        // Initialization failed
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        ServiceStatus.dwWin32ExitCode = -1;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;
    }

    // We report the running status to SCM.
    ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hStatus, &ServiceStatus);

    MEMORYSTATUS memory;
    // The worker loop of a service
    while(ServiceStatus.dwCurrentState == SERVICE_RUNNING)
    {
        char buffer[16];
        GlobalMemoryStatus(&memory);
        sprintf(buffer, "%d", memory.dwAvailPhys);

        int result = WriteToLog(buffer);
        if(result)
        {
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            ServiceStatus.dwWin32ExitCode = -1;
            SetServiceStatus(hStatus, &ServiceStatus);
            return;
        }

        Sleep(SLEEP_TIME);
    }
    return;
}

// Service initialization
int InitService()
{
    int result;
    result = WriteToLog("Monitoring started.");
    return result;
}

在service control handler中, 會針對SCM所送出的request呼叫相對應的處理程式. 可以接受的request種類則是在ServiceMain註冊service control handler時所設定. 基本上SERVICE_CONTROL_STOP和SERVICE_CONTROL_SHUTDOWN的處理方式一樣, 用來關閉service, 差別在於SERVICE_CONTROL_SHUTDOWN是在系統關機時, 由SCM發送給每個service.

void ControlHandler(DWORD request)
{
    switch(request)
    {
        case SERVICE_CONTROL_STOP:
            WriteToLog("Monitoring stopped.");
            ServiceStatus.dwWin32ExitCode = 0;
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            SetServiceStatus(hStatus, &ServiceStatus);
            return;
        case SERVICE_CONTROL_SHUTDOWN:
            WriteToLog("Monitoring stopped.");
            ServiceStatus.dwWin32ExitCode = 0;
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            SetServiceStatus(hStatus, &ServiceStatus);
            return;
        default:
            break;
    }

    // Report current status
    SetServiceStatus(hStatus, &ServiceStatus);
}

要安裝service可以利用系統提供的command line utility, 如下所示. 要注意的是, binpath=後面必須有一個空格.

sc create MemoryStatus binpath= c:\Temp\MemoryStatus.exe

要刪除service也同樣可以使用系統提供工具, 如下所示.

sc delete MemoryStatus

 

參考資料:

在Windows XP上安裝Windows CE模擬器出現錯誤

安裝Microsoft eMbedded Visual C++在Windows XP上時出現了"虛擬 PC / Windows CE 模擬器' 將造成 Windows 變得不穩定。 Windows 已禁止載入這些驅動程式。"這個訊息, 則無法開啟Windows CE模擬器來測試所撰寫的Windows CE程式. 要解決這個問題很簡單, 只要稍微修改一下C:\Boot.ini這個檔案的內容就可以了. 修改步驟如下:

  1. 在桌面上"我的電腦"的圖示上按滑鼠右鍵, 選擇內容開啟"系統內容"
  2. 選擇"進階"頁面
  3. 在視窗下方的"啟動及修復"方塊中按一下"設定"
  4. 在出現的"啟動及修復"視窗中按一下"編輯"
  5. 然後將"/noexecute=optin"刪除, 並加上"/execute"
  6. 存檔後重新開機就大功告成了

參考資料:

星期五, 3月 13, 2009

Install VMware workstation v6.0.0.45731 on Ubuntu 8.0.4

After installing VMware workstation on Ubuntu 8.0.4, a compiler error which says "conflicting types for ‘poll_initwait’" will raise. The same error will also generate when you run vmware-config.pl to configure the VMware. We can fix the problem in the following steps:

  1. Download the patch from Petr Vandrovec at http://knihovny.cvut.cz/ftp/pub/vmware/vmware-any-any-update115.tar.gz.
  2. tar xfz vmware-any-any-update115.tar.gz
  3. Change the working directory into vmware-any-any-update115
  4. sudo ./runme.pl

Then, you will get another compiler error which says "only <linux/bitops.h> can be included directly". Fix the probelm in the following steps:

  1. cd /usr/lib/vmware/modules/source
  2. cp vmmon.tar vmmon.tar.orig
  3. sudo tar xvf vmmon.tar
  4. cd vmmon-only/include/
  5. sudo vi vcpuset.h
  6. change line 74 from: #include "asm/bitops.h" to #include "linux/bitops.h"
  7. rm vmmon.tar
  8. sudo tar cvf vmmon.tar vmmon-only/
  9. sudo rm -rf vmmon-only/
  10. sudo vmware-config.pl

星期五, 3月 06, 2009

Static initialization block and initializer block

Static initialization block在類別載入時會執行該區塊中的程式碼, 而且整個程式的執行過程中只會執行一次.

Initializer block則是在每個物件被建立時執行該區塊中的程式碼, 接著才執行contructor中的程式碼.

class ClassA {
    // static initialization block
    static {
        System.out.println("This is static initialization blocks");
    }

    // initializer block
    {
        System.out.println("This is initializer block");
    }

    public ClassA()
    {
        System.out.println("Constructor A");
    }

    public void print()
    {
        System.out.println("I am A");
    }

    public static void staticPrint()
    {
        System.out.println("Static print");
    }
}

public class Test01 {
    public static void main(String[] args) {
        System.out.println("Start testing...");
        ClassA.staticPrint();
        ClassA a = new ClassA();
        a.print();
    }
}

星期日, 3月 01, 2009

Java的String串接

String物件的長度是固定的, 不能改變它的內容. 在程式中, 使用+來串接字串實際上會產生新的字串物件. 如果程式中此動作非常頻繁, 程式會變得比較沒有效率.

在J2SE 5.0之前, 可以使用StringBuffer來做這些字串的處理, 從J2SE 5.0開始, 也可以使用StringBuilder來做相同的事情. 這兩個類別的差別在於多執行緒的同步管理. 如果程式是多執行緒程式, 則使用StringBuffer, 因為StringBuilder沒有處理同步的問題.

public class AppendStringTest {
    public static void main(String[] args) {
        StringBuilder builder = new StringBuilder("");
        long beginTime = System.currentTimeMillis();
        for(int i=0; i<10000; i++)
            builder.append(String.valueOf(i));
        long endTime = System.currentTimeMillis();
        System.out.println("執行時間: "+(endTime-beginTime));
        String text = "";
        beginTime = System.currentTimeMillis();
        for(int i=0; i<10000; i++)
            text = text + i;
        endTime = System.currentTimeMillis();
        System.out.println("執行時間: "+(endTime-beginTime));
    }
}

Java的String pool

Java執行時會維護一個String pool, 對於一些可以共享的字串物件, 會先在String pool中尋找, 有相同的字串內容就直接傳回, 減少記憶體的耗用.

public class test02 {
    public static void main(String args[])
    {
        String a = new String("abc");
        String b = new String("abc");
        String c = "abc";
        String d = "abc";
        String e = "def";
        String f = "abcdef";
        String g = c+e;
        String h = (c+e).intern(); 
        String i = new String("abc").intern();

        System.out.println(a == b);    // false
        System.out.println(c == d);    // true
        System.out.println(f == g);    // false
        System.out.println(f == h);    // true
    }
}

星期四, 2月 05, 2009

Java中的foreach

J2SE 5.0之後新增了foreach的語法, 可用於存取陣列元素. 以下為一些簡單的範例:

一維陣列

public class test02 {
    public static void main(String args[])
    {
        int[] a = new int[] {1, 2, 3, 4, 5};

        for(int v : a)
            System.out.println(v);
    }
}

二維陣列

public class test02 {
    public static void main(String args[])
    {
        int[][] a = new int[][] {
            {1, 2, 3, 4, 5},
            {10, 11, 12}
        };

        for(int[] row : a) {
            for(int element : row)
                System.out.print(element + " ");
            System.out.println();
        }
    }
}