1. 得到某個對象的屬性
1 public Object getProperty(Object owner, String fieldName) throws Exception {
2 Class ownerClass = owner.getClass();
3
4 Field field = ownerClass.getField(fieldName);
5
6 Object property = field.get(owner);
7
8 return property;
9 }
Class ownerClass = owner.getClass():得到該對象的Class。
Field field = ownerClass.getField(fieldName):通過Class得到類聲明的屬性。
Object property = field.get(owner):通過對象得到該屬性的實例,如果這個屬性是非公有的,這里會報IllegalAccessException。
2. 得到某個類的靜態屬性
1 public Object getStaticProperty(String className, String fieldName)
2 throws Exception {
3 Class ownerClass = Class.forName(className);
4
5 Field field = ownerClass.getField(fieldName);
6
7 Object property = field.get(ownerClass);
8
9 return property;
10 }
Class ownerClass = Class.forName(className) :首先得到這個類的Class。
Field field = ownerClass.getField(fieldName):和上面一樣,通過Class得到類聲明的屬性。
Object property = field.get(ownerClass) :這里和上面有些不同,因為該屬性是靜態的,所以直接從類的Class里取。
3. 執行某對象的方法
1 public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
2
3 Class ownerClass = owner.getClass();
4
5 Class[] argsClass = new Class[args.length];
6
7 for (int i = 0, j = args.length; i < j; i++) {
8 argsClass[i] = args[i].getClass();
9 }
10
11 Method method = ownerClass.getMethod(methodName, argsClass);
12
13 return method.invoke(owner, args);
14 }
Class owner_class = owner.getClass() :首先還是必須得到這個對象的Class。
5~9行:配置參數的Class數組,作為尋找Method的條件。
Method method = ownerClass.getMethod(methodName, argsClass):通過Method名和參數的Class數組得到要執行的Method。
method.invoke(owner, args):執行該Method,invoke方法的參數是執行這個方法的對象,和參數數組。返回值是Object,也既是該方法的返回值。
4. 執行某個類的靜態方法
1 public Object invokeStaticMethod(String className, String methodName,
2 Object[] args) throws Exception {
3 Class ownerClass = Class.forName(className);
4
5 Class[] argsClass = new Class[args.length];
6
7 for (int i = 0, j = args.length; i < j; i++) {
8 argsClass[i] = args[i].getClass();
9 }
10
11 Method method = ownerClass.getMethod(methodName, argsClass);
12
13 return method.invoke(null, args);
14 }
基本的原理和實例3相同,不同點是最后一行,invoke的一個參數是null,因為這是靜態方法,不需要借助實例運行。
5. 新建實例
1
2 public Object newInstance(String className, Object[] args) throws Exception {
3 Class newoneClass = Class.forName(className);
4
5 Class[] argsClass = new Class[args.length];
6
7 for (int i = 0, j = args.length; i < j; i++) {
8 argsClass[i] = args[i].getClass();
9 }
10
11 Constructor cons = newoneClass.getConstructor(argsClass);
12
13 return cons.newInstance(args);
14
15 }
這里說的方法是執行帶參數的構造函數來新建實例的方法。如果不需要參數,可以直接使用newoneClass.newInstance()來實現。
Class newoneClass = Class.forName(className):第一步,得到要構造的實例的Class。
第5~第9行:得到參數的Class數組。
Constructor cons = newoneClass.getConstructor(argsClass):得到構造子。
cons.newInstance(args):新建實例。
6. 判斷是否為某個類的實例
1 public boolean isInstance(Object obj, Class cls) {
2 return cls.isInstance(obj);
3 }
7. 得到數組中的某個元素
1 public Object getByArray(Object array, int index) {
2 return Array.get(array,index);
3 }
其中,反射機制最重要的部分是允許你檢查類的結構。java.lang.reflect包中的三個類Field,Method,Constructor類分別描述類的字段,方法和構造器,它們都有一個getName方法,用來返回相應條目的名稱。
2。使用java.util.ResourceBundle類的getBundle()方法
示例: ResourceBundle rb = ResourceBundle.getBundle(name, Locale.getDefault());
3。使用java.util.PropertyResourceBundle類的構造函數
示例: InputStream in = new BufferedInputStream(new FileInputStream(name));
ResourceBundle rb = new PropertyResourceBundle(in);
4。使用class變量的getResourceAsStream()方法
示例: InputStream in = JProperties.class.getResourceAsStream(name);
Properties p = new Properties();
p.load(in);
5。使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法
示例: InputStream in = JProperties.class.getClassLoader().getResourceAsStream(name);
Properties p = new Properties();
p.load(in);
6。使用java.lang.ClassLoader類的getSystemResourceAsStream()靜態方法
傳遞引用
既然說java中的參數傳遞只有by value一種,為什么還要說傳遞引用呢?實際上,java與C++一樣,同樣存在對一個對象的引用進行傳遞的問題,但java中的引用傳遞機制是,把原來變量中保存的內存地址傳遞作為一個參數進行傳遞,而不是直接把引用傳過去。所以在java中仍把它稱做按值傳參。
同樣采用例子的方式來解釋java中的引用傳遞的問題:
.......
public static void changAge(User user){
User temp = user;//這時,temp中存放了和原對象相同的內存地址
temp.age = temp.age + 20;//對user的年齡進行增加的操作,
/*是對temp所指向的內存空間中的值直接進行操作,所以會對原對象的值造成影響。就相當于是傳遞了原對象的引用*/
}
......
User user = new User("li",25);//仍采用上例中的User
changAge(user);//改變user的年齡
System.out.println(user.age);//45
.......
有了上面例子的說明,我們可能就會想到,如果我們的程序中私有變量是一個對象類型的變量時,在主程序中有了這個私有變量的拷貝,是不是就有可能在修改這個拷貝時不小心把原來的私有變量的值也給改變了呢?
我們來看下面的例子:
class Test{
private Date date=new Date();
public Date getDate(){
return date;
}
public static void main(String[] args){
Test tt=new Test();
Date myDate=tt.getDate();//返回了一個私有變量的拷貝
System.out.println(myDate);
myDate.setTime(new Date().getTime()-(long)(10*365.25*24*3600*1000));//對新產生的拷貝進行修改
System.out.println(tt.getDate());
System.out.println(myDate);
}
}
先來猜一下運行的結果,是前兩句輸出一樣呢還是后兩句輸出一樣(最后一句輸出比第一句輸出的日期早十年)?很多人都會說是前兩句輸出一樣.實際上,你會驚奇地發現,輸出結果顯示后兩者輸出一樣,私有變量在程序外部被改變了,程序的封裝性遭到了破壞。
出錯的原因很微妙.因為myDate和tt指向了同一個對象,對myDate的引用更改方法自動地改變了這個類的私有方法狀態。經過測試可以知道,如果myDate被重新賦值(比如myDate=new Date()),就不會出現上面的結果。但是現在的這個程序,私有變量還是在程序外部被改變了。
如果需要返回一個指向可變對象的引用,我們就需要克隆它,這樣就不會導致上面的私有變量被更改。
上面程序就應更改為:return (Date)date.clone();就可以防止私有變量被修改的麻煩了。
再來執行上面的程序,就會出現不一樣的結果。
我之前為了給一個java項目添加IC卡讀寫功能,曾經查了很多資料發現查到的資料都是只說到第二步,所以剩下的就只好自己動手研究了.下面結合具體的代碼來按這三個步驟分析.
1>假設廠商提供的.h文件中定義了一個我們需要的方法:
__int16 __stdcall readData( HANDLE icdev, __int16 offset, __int16 len, unsigned char *data_buffer );
a.__int16定義了一個不依賴于具體的硬件和軟件環境,在任何環境下都占16 bit的整型數據(java中的int類型是32 bit),這個數據類型是vc++中特定的數據類型,所以我自己做的dll也是用的vc++來編譯.
b.__stdcall表示這個函數可以被其它程序調用,vc++編譯的DLL欲被其他語言編寫的程序調用,應將函數的調用方式聲明為__stdcall方式,WINAPI都采用這種方式.c/c++語言默認的調用方式是__cdecl,所以在自己做可被java程序調用的dll時一定要加上__stdcall的聲明,否則在java程序執行時會報類型不匹配的錯誤.
c.HANDLE icdev是windows操作系統中的一個概念,屬于win32的一種數據類型,代表一個核心對象在某一個進程中的唯一索引,不是指針,在知道這個索引代表的對象類型時可以強制轉換成此類型的數據.
這些知識都屬于win32編程的范圍,更為詳細的win32資料可以查閱相關的文檔.
這個方法的原始含義是通過設備初始時產生的設備標志號icdev,讀取從某字符串在內存空間中的相對超始位置offset開始的共len個字符,并存放到data_buffer指向的無符號字符類型的內存空間中,并返回一個16 bit的整型值來標志這次的讀設備是否成功,這里真正需要的是unsigned char *這個指針指向的地址存放的數據,而java中沒有指針類型,所以可以考慮定義一個返回字符串類型的java方法,原方法中返回的整型值也可以按經過一定的規則處理按字符串類型傳出,由于HANDLE是一個類型于java中的Ojbect類型的數據,可以把它當作int類型處理,這樣java程序中的方法定義就已經形成了:
String readData( int icdev, int offset, int len );
聲明這個方法的時候要加上native關鍵字,表明這是一個與本地方法通信的java方法,同時為了安全起見,此文方法要對其它類隱藏,使用private聲明,再另外寫一個public方法去調用它,同時要在這個類中把本地文件加載進來,最終的代碼如下:
package test;
public class LinkDll
{
//從指定地址讀數據
private native String readData( int icdev, int offset, int len );
public String readData( int icdev, int offset, int len )
{
return this.readDataTemp( icdev, offset, len );
}
static
{
System.loadLibrary( "TestDll" );//如果執行環境是linux這里加載的是SO文件,如果是windows環境這里加載的是dll文件
}
}
2>使用JDK的javah命令為這個類生成一個包含類中的方法定義的.h文件,可進入到class文件包的根目錄下(只要是在classpath參數中的路徑即可),使用javah命令的時候要加上包名javah test.LinkDll,命令成功后生成一個名為test_LinkDll.h的頭文件.
文件內容如下:
/* DO NOT EDIT THIS FILE - it is machine generated*/
#include <jni.h>
/* Header for class test_LinkDll */
#ifndef _Included_test_LinkDll #define
Included_test_LinkDll
#ifdef __cplusplus extern "C" { #endif
/*
* Class: test_LinkDll
* Method: readDataTemp
* Signature: (III)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_test_LinkDll_readDataTemp(JNIEnv *, jobject, jint, jint, jint);
#ifdef __cplusplus } #endif
#endif
可以看出,JNI為了實現和dll文件的通信,已經按它的標準對方法名/參數類型/參數數目作了一定的處理,其中的JNIEnv*/jobjtct這兩個參數是每個JNI方法固有的參數,javah命令負責按JNI標準為每個java方法加上這兩個參數.JNIEnv是指向類型為JNIEnv_的一個特殊JNI數據結構的指針,當由C++編譯器編譯時JNIEnv_結構其實被定義為一個類,這個類中定義了很多內嵌函數,通過使用"->"符號,可以很方便使用這些函數,如:
(env)->NewString( jchar* c, jint len )
可以從指針c指向的地址開始讀取len個字符封裝成一個JString類型的數據.
其中的jchar對應于c/c++中的char,jint對應于c/c++中的len,JString對應于java中的String,通過查看jni.h可以看到這些數據類型其實都是根據java和c/c++中的數據類型對應關系使用typedef關鍵字重新定義的基本數據類型或結構體.
具體的對應關系如下:
Java類型 本地類型 描述
boolean jboolean C/C++8位整型
byte jbyte C/C++帶符號的8位整型
char jchar C/C++無符號的16位整型
short jshort C/C++帶符號的16位整型
int jint C/C++帶符號的32位整型
long jlong C/C++帶符號的64位整型e
float jfloat C/C++32位浮點型
double jdouble C/C++64位浮點型
Object jobject 任何Java對象,或者沒有對應java類型的對象
Class jclass Class對象
String jstring 字符串對象
Object[] jobjectArray 任何對象的數組
boolean[] jbooleanArray 布爾型數組
byte[] jbyteArray 比特型數組
char[] jcharArray 字符型數組
short[] jshortArray 短整型數組
int[] jintArray 整型數組
long[] jlongArray 長整型數組
float[] jfloatArray 浮點型數組
double[] jdoubleArray 雙浮點型數組
更為詳細的資料可以查閱JNI文檔.
需要注意的問題:test_LinkDll.h文件包含了jni.h文件;
3>使用vc++ 6.0編寫TestDll.dll文件,這個文件名是和java類中loadLibrary的名稱一致.
a>使用vc++6.0 新建一個Win32 Dynamic-Link Library的工程文件,工程名指定為TestDll
b>把源代碼文件和頭文件使用"Add Fiels to Project"菜單加載到工程中,若使用c來編碼,源碼文件后綴名為.c,若使用c++來編碼,源碼文件擴展名為.cpp,這個一定要搞清楚,因為對于不同的語言,使用JNIEnv指針的方式是不同的.
c>在這個文件里調用設備商提供的dll文件,設備商一般提供三種文件:dll/lib/h,這里假設分別為A.dll/A.lib/A.h.
這個地方的調用分為動態調用和靜態調用靜態調用即是只要把被調用的dll文件放到path路徑下,然后加載lib鏈接文件和.h頭文件即可直接調用A.dll中的方法:
把設備商提供的A.h文件使用"Add Fiels to Project"菜單加載到這個工程中,同時在源代碼文件中要把這個A.h文件使用include包含進來;
然后依次點擊"Project->settings"菜單,打開link選項卡,把A.lib添加到"Object/library modules"選項中.
具體的代碼如下:
//讀出數據,需要注意的是如果是c程序在調用JNI函數時必須在JNIEnv的變量名前加*,如(*env)->xxx,如果是c++程序,則直接使用(env)->xxx
#include<WINDOWS.H>
#include<MALLOC.H>
#include<STDIO.H>
#include<jni.h>
#include "test_LinkDll.h"
#include "A.h"
JNIEXPORT jstring JNICALL Java_test_LinkDll_readDataTemp( JNIEnv *env, jobject jo, jint ji_icdev, jint ji_len )
{
//*************************基本數據聲明與定義******************************
HANDLE H_icdev = (HANDLE)ji_icdev;//設備標志符
__int16 i16_len = (__int16)ji_len;//讀出的數據長度,值為3,即3個HEX形式的字符
__int16 i16_result;//函數返回值
__int16 i16_coverResult;//字符轉換函數的返回值
int i_temp;//用于循環的中間變量
jchar jca_result[3] = { 'e', 'r', 'r' };//當讀數據錯誤時返回此字符串
//無符號字符指針,指向的內存空間用于存放讀出的HEX形式的數據字符串
unsigned char* uncp_hex_passward = (unsigned char*)malloc( i16_len );
//無符號字符指針,指向的內存空間存放從HEX形式轉換為ASC形式的數據字符串
unsigned char* uncp_asc_passward = (unsigned char*)malloc( i16_len * 2 );
//java char指針,指向的內存空間存放從存放ASC形式數據字符串空間讀出的數據字符串
jchar *jcp_data = (jchar*)malloc(i16_len*2+1);
//java String,存放從java char數組生成的String字符串,并返回給調用者
jstring js_data = 0;
//*********讀出3個HEX形式的數據字符到uncp_hex_data指定的內存空間**********
i16_result = readData( H_icdev, 6, uncp_hex_data );//這里直接調用的是設備商提供的原型方法.
if ( i16_result != 0 )
{
printf( "讀卡錯誤......\n" );
//這個地方調用JNI定義的方法NewString(jchar*,jint),把jchar字符串轉換為JString類型數據,返回到java程序中即是String
return (env)->NewString( jca_result, 3 );
}
printf( "讀數據成功......\n" );
//**************HEX形式的數據字符串轉換為ASC形式的數據字符串**************
i16_coverResult = hex_asc( uncp_hex_data, uncp_asc_data, 3 );
if ( i16_coverResult != 0 )
{
printf( "字符轉換錯誤!\n" );
return (env)->NewString( jca_result, 3 );
}
//**********ASC char形式的數據字符串轉換為jchar形式的數據字符串***********
for ( i_temp = 0; i_temp < i16_len; i_temp++ )
jcp_data[i_temp] = uncp_hex_data[i_temp];
//******************jchar形式的數據字符串轉換為java String****************
js_data = (env)->NewString(jcp_data,i16_len);
return js_data;
}
動態調用,不需要lib文件,直接加載A.dll文件,并把其中的文件再次聲明,代碼如下:
#include<STDIO.H>
#include<WINDOWS.H>
#include "test_LinkDll.h"
//首先聲明一個臨時方法,這個方法名可以隨意定義,但參數同設備商提供的原型方法的參數保持一致.
typedef int ( *readDataTemp )( int, int, int, unsigned char * );//從指定地址讀數據
//從指定地址讀數據
JNIEXPORT jstring JNICALL Java_readDataTemp( JNIEnv *env, jobject jo, jint ji_icdev, jint ji_offset, jint ji_len )
{
int i_temp;
int i_result;
int i_icdev = (int)ji_icdev;
int i_offset = (int)ji_offset;
int i_len = (int)ji_len;
jchar jca_result[5] = { 'e', 'r', 'r' };
unsigned char *uncp_data = (unsigned char*)malloc(i_len);
jchar *jcp_data = (jchar *)malloc(i_len);
jstring js_data = 0;
//HINSTANCE是win32中同HANDLE類似的一種數據類型,意為Handle to an instance,常用來標記App實例,在這個地方首先把A.dll加載到內存空間,以一個App的形式存放,然后取
得它的instance交給dllhandle,以備其它資源使用.
HINSTANCE dllhandle;
dllhandle = LoadLibrary( "A.dll" );
//這個地方首先定義一個已聲明過的臨時方法,此臨時方法相當于一個結構體,它和設備商提供的原型方法具有相同的參數結構,可互相轉換
readDataTemp readData;
//使用win32的GetProcAddress方法取得A.dll中定義的名為readData的方法,并把這個方法轉換為已被定義好的同結構的臨時方法,
//然后在下面的程序中,就可以使用這個臨時方法了,使用這個臨時方法在這時等同于使用A.dll中的原型方法.
readData = (readDataTemp) GetProcAddress( dllhandle, "readData" );
i_result = (*readData)( i_icdev, i_offset, i_len, uncp_data );
if ( i_result != 0 )
{
printf( "讀數據失敗......\n" );
return (env)->NewString( jca_result, 3 );
}
for ( i_temp = 0; i_temp < i_len; i_temp++ )
{
jcp_data[i_temp] = uncp_data[i_temp];
}
js_data = (env)->NewString( jcp_data, i_len );
return js_data;
}
4>以上即是一個java程序調用第三方dll文件的完整過程,當然,在整個過程的工作全部完成以后,就可以使用java類LinkDll中的public String radData( int, int, int )方法了,效果同直接使用c/c++調用這個設備商提供的A.dll文件中的readData方法幾乎一樣.
總結:JNI技術確實是提高了java程序的執行效率,并且擴展了java程序的功能,但它也確確實實破壞了java程序的最重要的優點:平臺無關性,所以除非必須(不得不)使用JNI技術,一般還是提倡寫100%純java的程序.根據自己的經驗及查閱的一些資料,把可以使用JNI技術的情況羅列如下:
1>需要直接操作物理設備,而沒有相關的驅動程序,這時候我們可能需要用C甚至匯編語言來編寫該設備的驅動,然后通過JNI調用;
2>涉及大量數學運算的部分,用java會帶來些效率上的損失;
3>用java會產生系統難以支付的開銷,如需要大量網絡鏈接的場合;
4>存在大量可重用的c/c++代碼,通過JNI可以減少開發工作量,避免重復開發.
另外,在利用JNI技術的時候要注意以下幾點:
1>由于Java安全機制的限制,不要試圖通過Jar文件的方式發布包含本地化方法的Applet到客戶端;
2>注意內存管理問題,雖然在本地方法返回Java后將自動釋放局部引用,但過多的局部引用將使虛擬機在執行本地方法時耗盡內存;
3>JNI技術不僅可以讓java程序調用c/c++代碼,也可以讓c/c++代碼調用java代碼.
注:有一個名叫Jawin開源項目實現了直接讀取第三方dll文件,不用自己辛苦去手寫一個起傳值轉換作用的dll文件,有興趣的可以研究一下.但是我用的時候不太順手,有很多規則限制,像自己寫程序時可以隨意定義返回值,隨意轉換類型,用這個包的話這些都是不可能的了,所以我的項目還沒開始就把它拋棄了.
轉自:http://hi.baidu.com/dinguangx/blog/item/c6f5003ddcd688c19e3d6279.html
其中plugin.txt 文件中的內容為(自定義的內容,可以根據自己的習慣設置):
s = select * from
sc* = select count(*) from
w = where
ss = select /*+parallel(a,6)*/ * from
打開pl/sql developer進入[首選項]->[用戶界面]->[編輯器]->[autoreplace],選中enabled復選框,再查找 plugin.txt所在的路徑,點擊[應用]即完成插件的安裝。
重啟pl/sql developer,打開sql編輯窗口,輸入s,再按空格,就可以出現select * from,這樣就可以不必每次都輸入這段經常使用而又經常打錯的語句了。
vi ~/.emacs
然后重新啟動 emacs ,效率很低 ,暗自嘟囔, emacs 怎么沒有這種功能,不重起,就自動更新 .emacs 的設置 呢?
后來我發現,這個功能完全沒有必要,我的做法是:
都是立即生效,可以馬上試驗一條語句的效果。 例如,在任何一個文件中,寫
(setq frame-title-format "emacs@%b")
把光標停在在這條語句后面, C-x C-e ,馬上看到 emacs 的 標題欄上發生變化。
我用這種方法調試我的每一個小的配置文件,按上篇文章說的方法, 把他放在 ~/Emacs/myconfig/my-site-start.d 中。
轉自:http://ann77.emacser.com/Emacs/EmacsDotEmacsWithoutRestart.html
C-x C-c : 退出Emacs
C-x C-f : 打開一個文件,如果文件不存在,則創建一個文件
C-g : 取消未完成的命令
C-z (redefined): Undo;原來C-z是掛起Emacs(然后用fg命令調出);C-x u 是默認的命令; 移動一下光標,再C-z就可以redo
M-d : 刪除光標后的詞語
C-v : 向前翻頁
M-v : 向后翻頁
M-r : 將光標移動到屏幕中間那行
C-a : 移到行首
M-a : 移到句首,從行首到句首之間可能有空格
C-e : 移到行尾
M-e : 移到句尾
M-{ : 向上移動一段
M-} : 向下移動一段
C-right : 向前移動一個單詞
C-left : 向后移動一個單詞
C-up : 向前移動一段
C-down : 向后移動一段
M-< : 移到整個文本開頭
M-> : 移到整個文本末尾
C-u 數字 命令 : 執行多次(數字表示次數)該命令;“M-數字 命令” 也可以
M-x goto-line : 移動到某一行
C-l : 重繪屏幕,效果就是當前編輯行移動窗口中央
C-x k : 關閉當前buffer
C-x b : 切換到前一個編輯的buffer
C-x C-b : 列出當前所有buffer
C-x C-s : 保存當前buffer
C-x s : 保存所有未保存的buffer,會提示你是否需要保存
C-x C-w : 文件另存為
M-space (redefined): 設置mark; C-@ 是默認命令
C-w (redefined) : 剪切一塊區域;如果沒有設置mark,則是剪切一行
M-w (redefined) : 拷貝一塊區域;如果沒有設置mark, 則是拷貝一行
C-k : 從當前位置剪切到行尾
C-y : 粘貼
M-y : 用C-y拉回最近被除去的文本后,換成 M-y可以拉回以前被除去的文本。鍵入多次的M-y可以拉回更早以前被除去的文本。
C-x r k : 執行矩形區域的剪切
C-x r y : 執行矩形區域的粘貼
C-x 0 : 關閉當前窗口
C-x 1 : 將當前窗口最大化
C-x 2 : 垂直分割窗口
C-x 3 : 水平分割窗口
M-o (redefined) : 在窗口之間切換; C-x o 是默認命令
C-x 5 1/2/3/0 : 對frame類似的操作
C-x < : 窗口內容右卷
C-x > : 窗口內容左卷(這兩個命令在垂直分割窗口后比較有用)
(C-u) C-x ^ : 加高當前窗口,如果有C-u,則每次加高4行
(C-u) C-x } : 加寬當前窗口
(C-u) C-x { : 壓窄當前窗口
ESC C-v : 在其它窗口進行卷屏操作
C-s : 向前搜索(增量式搜索);連續C-s,跳到下一個搜索到的目標
C-s RET : 普通搜索
C-r : 向前搜索
C-s RET C-w : 按單詞查詢
M-% : 查詢替換,也就是替換前會詢問一下
M-x replace-string : 普通替換
M-! etags .c .h : 創建TAGS文件
M-. : 跳到tag所在位置
M-x list-tags : 列出tags
C-x r m : 設置書簽bookmark
C-x r b : 跳到bookmark處
C-h ? : 查看幫助信息
C-h f : 查看一個函數
C-h v : 查看一個變量
C-h k : 查看一個鍵綁定 (C-h c 也是查看鍵綁定,但是信息較簡略)
C-h C-f : 查看一個函數的Info,非常有用
C-h i : 看Info
C-M-\ : 對選中區域,按照某種格式(比如C程序)進行格式化
C-x h : 全部選中
M-! : 執行外部shell命令
M-x shell : 模擬shell的buffer
M-x term : 模擬terminal, C-c k 關閉terminal
C-x C-q : 修改buffer的只讀屬性
翻頁
C-v 下一頁
M-v 上一頁
選擇
M-h 選擇段落
C-x h 全部選擇
普通區塊
C-SPC M-x set-mark-command 單個位置set mark
C-@ 同上
M-@ 對word進行set Mark
M-w 先set Mark,移到光標,M-w就可以復制
C-w 剪切
矩形區塊
用這些快捷鍵要先關閉cua-mode
C-x r t 用串填充矩形區域
C-x r o 插入空白的矩形區域
C-x r y 插入之前刪除的矩形區域, 粘貼時,矩形左上角對齊光標
C-x r k 刪除矩形區域
C-x r c 將當前矩形區域清空
寄存器
----------------------------------------------------------------------
光標位置和窗口狀態
C-x r SPC <寄存器名> 存貯光標位置
C-x r w <寄存器名> 保存當前窗口狀態
C-x r f <寄存器名> 保存所有窗口狀態
C-x r j <寄存器名> 光標跳轉
文本和數字
C-x r s <寄存器名> 將連續區塊拷貝到寄存器中
C-x r r <寄存器名> 將矩形區塊拷貝到寄存器中
C-u <數字> C-x r n <寄存器名> 將數字拷貝到寄存器中
C-x r i <寄存器名> 在緩沖區中插入寄存器內容
M-x view-register 查看寄存器內容
M-x list-registers 查看寄存器列表
宏模式
C-x ( 開始一個宏的定義
C-x ) 結束一個宏的定義
C-x e 執行宏
M-x name-last-kbd-macro 給最后一個宏命名
M-x insert-kbd-macro 在當前文件中插入一個已定義并命名過的宏
書簽
C-x r m <name> 設置書簽
C-x r b <name> 跳轉到書簽
C-x r l 書簽列表
M-x bookmark-delete 刪除書簽
M-x bookmark-load 讀取存儲書簽文件
M-x bookmark-save 保存到文件
目錄模式
----------------------------------------------------------------------
C-x d M-x dired 啟動目錄模式
C-x C-d 簡單目錄
程序
C-x C-z 掛起程序
C-c C-x 退出程序
C-c k 關閉buffer
C-l 重畫屏幕
C-g 結束命令,或者假死中恢復,也可以按3次ESC
文件
C-x C-s 保存
C-x C-w 另存為
C-x C-f 打開文件
C-x C-r 只讀方式打開
C-x C-v 讀入另外一個文件代替當前buffer的文件
C-x s 保存所有
C-x i 將文件的內容插入
M-x revert-buffer 恢復到原始狀態
跳轉
前/后 單位
C-f/b 字
M-f/b 詞
C-a/e 行內
M-a/e 句
M-</> 文檔
C-p/n 行間
M-{/} 段落
C-x ]/[ 頁
C-x C-x 文件內,mark之間
M-g g 跳到指定行
M-x goto-char 跳到指定字符
編輯
M-u 后面單詞變為大寫
M-l 后面單詞變為小寫
M-c 后面單詞的首字母變大寫
M-/ 補全
C-j 從當前位置分成兩行,相當于RET + tab
M-( 插入()
C-q tab 插入tab
C-q C-m 插入^M
M-; 插入注釋
C-o 回車
刪除
M-d 后一詞
C-d 后一字
M-del 前一詞
M-k 到句尾
M-" 前面的所有空白
M-z 刪到指定字母處
C-k 刪除到行尾
文本換位
C-t 字符
M-t 單詞
C-x C-t 行
M-x transpose-* 其他命令
撤銷
C-/
C-x u
C-_
C-z
重做
C-g M-x undo
C-g C-/
C-g C-z
C-g C-_
粘貼
C-y
C-v
tab/空格轉換
M-x tabify
M-x untabify
讓選擇的區塊自動對齊
M-x indent-region
其他命令
C-u <數字> <命令> 重復命令n次
M-<數字> <命令> 同上
M-! 運行shell命令
C-u M-! 執行一條外部命令,并輸出到光標位置
M-x cd 改變工作目錄
M-x pwd 當前工作目錄
C-" 啟動輸入法
M-` 菜單
F10 菜單
M-x eval-buffer 在.emacs的buffer中運行,重新加載emacs配置
查找替換
----------------------------------------------------------------------
C-r 向上查找
C-s 向下查找
C-s C-w 向下查找,光標位置的單詞作為查找字符串
C-s C-y 向下查找,光標位置到行尾作為查找字符串
C-s RET <查找字符串> RET 非遞增查找
C-s RET C-w 不受換行、空格、標點影響
C-M-s 正則式向下查找
用向上查找命令就將上面命令的s替換為r
M-% 替換
C-M-% 正則式替換
y 替換當前的字符串并移動到下一個字符串
n 不替換當前字符串,直接移動到下一個字符串
! 進行全局替換,并要求不再顯示
. 替換當前字符串,然后退出查找替換操作
q 退出查找替換操作,光標定位到操作開始時的位置
其他命令
M-x replace-*
M-x search-*
窗口
C-x 0 關掉當前窗口
C-x 1 關掉其他窗口
C-x o 切換窗口
C-x 2 水平兩分窗口
C-x 3 垂直兩分窗口
C-x 5 2 新frame
buffer
C-x C-b 查看
C-x b 切換
C-x C-q 設為只讀
C-x k 刪除
C-x left/right 切換
一,配置JSF
把JSF2.0內的兩個開發包jsf-api.jar,jsf-impl.jar拷貝到Eclipse項目的lib目錄中(建立web項目略). 在web.xml中添加以下內容:
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
<param-value>-1</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.do</url-pattern> <!--此處名字可以隨便起,可以是*.action,*.faces 等 我習慣用*.do-->
</servlet-mapping>
這樣jsf框架已經添加進項目中了.接下來就要建立Bean了.如下所示:
package com.joy.jsf.beans;
//@ManagedBean(name="users") jsf2.0可以不用配置文件來管理bean
public class User {
private String userName;
private String userPassword;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String Check() {
if (!this.userName.equals("JOY") || !this.userPassword.equals("123456")) {
this.errorMessage = "名稱或密碼錯誤";
return "failure";
} else {
return "success";
}
}
}
之后要定制導航規則,新建face-config.xml 如下所示:
<faces-config>
<!-- <application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application> -->
<navigation-rule>
<from-view-id>/index.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/index.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<!--<managed-bean> <managed-bean-name>users</managed-bean-name> <managed-bean-class>
com.joy.jsf.beans.User </managed-bean-class> <managed-bean-scope>request</managed-bean-scope>
</managed-bean> -->
</faces-config>
配置文件建立完了,添加view頁面. index.jsp和welcome.jsp
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="f" uri=">
<%@ taglib prefix="h" uri=">
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首頁</title>
</head>
<body>
<f:view>
<h:form>
姓名:<h:inputText value="#{users.userName }" /><br/>
密碼:<h:inputText value="#{users.userPassword }"></h:inputText><br/>
<h:commandButton value="submit" action="#{users.Check}"></h:commandButton>
<br/>
<h:outputText value="#{users.errorMessage}"/><p>
</h:form>
</f:view>
</body>
</html>
welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="f" uri=">
<%@ taglib prefix="h" uri=">
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>歡迎回來</title>
</head>
<body>
<f:view>
<h:form>
Hello <h:outputText value="#{users.userName }"></h:outputText> ,Welcome to here!
</h:form>
</f:view>
</body>
</html>
保存,部署,運行http://localhost:8080/JSF/index.do
二,整合Spring
添加spring開發包,spring.jar,stadard.jar,commons-logging.jar,jstl.jar
web.xml 添加如下配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<description>添加Srping支持</description>
<display-name>Spring</display-name>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
然后在face-config.xml中添加
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
從spring工廠中獲取bean ,如果和jsf的托管bean一起使用,則托管bean的優先級要高于spring.
添加applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<bean id="users" class="com.joy.jsf.beans.User">
重新部署,運行. OK.
<beans xmlns="
xmlns:xsi="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
</bean>
</beans>
]]>