|
2007年4月20日
package cc.dynasoft.struts.action;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFFooter;
import org.apache.poi.hssf.usermodel.HSSFHeader;
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.Region;
import cc.dynasoft.bean.Department;
///import org.apache.poi.hssf.record.HeaderRecorder;
public class OutputExcel {
public static boolean outputExcel(ExcelArgs args, List title, List list) {
try {
int cellNum = args.getCellNum(); // workbook
int rowNum = args.getRowNum();
/**
* 建立表格設置。
*/
HSSFWorkbook wb = new HSSFWorkbook(); // create the new Workbook
HSSFSheet sheet = wb.createSheet(args.getSheetName()); // create
/**
* 打印設置
*/
HSSFPrintSetup hps = sheet.getPrintSetup();
hps.setPaperSize((short) 9); // 設置A4紙
// hps.setLandscape(true); // 將頁面設置為橫向打印模式
sheet.setHorizontallyCenter(true); // 設置打印頁面為水平居中
// sheet.setVerticallyCenter(true); // 設置打印頁面為垂直居中
wb.setPrintArea(0, "$A$2:$e$" + rowNum + 2);// 打印區域設置.
/**
* 設置表的Footer
*/
HSSFFooter footer = sheet.getFooter();
// 設置footer的位置和顯示的內容
footer.setCenter("Time:" + HSSFFooter.date());
footer.setRight("Page " + HSSFFooter.page() + " of "
+ HSSFFooter.numPages());
/**
* 設置表的Header
*/
// 設置header的位置,共有三種位置和相應的顯示設置
HSSFHeader header = sheet.getHeader();
// header.setRight("Center Header");
// header.setLeft("Left Header");
header.setCenter(HSSFHeader.font("Stencil-Normal", "Italic")
+ HSSFHeader.fontSize((short) 30) + args.getHeaderTitle());
// header.endDoubleUnderline();
header.startUnderline();
/**
* 設置列的寬度
*/
sheet.setColumnWidth((short) 2,
(short) ((30 * 8) / ((double) 1 / 10)));
sheet.setColumnWidth((short) 3,
(short) ((40 * 8) / ((double) 1 / 10)));
sheet.setColumnWidth((short) 4,
(short) ((50 * 8) / ((double) 1 / 20)));
/**
* 創建第一行,也就是顯示的標題, 可以高置的高度,單元格的格式,顏色,字體等設置. 同時可以合并單元格.
*/
HSSFRow row0 = sheet.createRow(0); // 創建0行
row0.setHeight((short) 0x300); // 設直行的高度.
HSSFFont font2 = wb.createFont(); // 創建字體格式
font2.setColor(HSSFFont.SS_NONE); // 設置單元格字體的顏色.
font2.setFontHeight((short) 700); // 設置字體大小
font2.setFontName("Courier New"); // 設置單元格字體
HSSFCell cell0 = row0.createCell((short) 0); // 創建0行0列.
HSSFCellStyle style3 = wb.createCellStyle(); // 創建單元格風格.
style3.setAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
style3.setAlignment(HSSFCellStyle.ALIGN_CENTER); // /水平居中
style3.setFont(font2); // 將字體格式加入到單元格風格當中
// cell0.setCellType()
cell0.setCellStyle(style3); // 設置單元格的風格.
cell0.setCellValue(args.getHeaderTitle()); // 設置單元的內容.
sheet.addMergedRegion(new Region(0, (short) 0, 0,
(short) (cellNum - 1)));// 指定合并區域,前二個參數為開始處X,Y坐標.后二個為結束的坐標.
/**
* 設置其它數據 設置風格
*/
HSSFCellStyle style = wb.createCellStyle();
style.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 設置單無格的邊框為粗體
style.setBottomBorderColor(HSSFColor.BLACK.index); // 設置單元格的邊框顏色.
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setLeftBorderColor(HSSFColor.BLACK.index);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
style.setRightBorderColor(HSSFColor.BLACK.index);
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
style.setTopBorderColor(HSSFColor.BLACK.index);
// style.setWrapText(true);//文本區域隨內容多少自動調整
// style.setFillForegroundColor(HSSFColor.LIME.index);
// style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
/**
* 設置風格1
*/
HSSFCellStyle style1 = wb.createCellStyle();
style1.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 設置單無格的邊框為粗體
style1.setBottomBorderColor(HSSFColor.BLACK.index); // 設置單元格的邊框顏色.
style1.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style1.setLeftBorderColor(HSSFColor.BLACK.index);
style1.setBorderRight(HSSFCellStyle.BORDER_THIN);
style1.setRightBorderColor(HSSFColor.BLACK.index);
style1.setBorderTop(HSSFCellStyle.BORDER_MEDIUM);
style1.setTopBorderColor(HSSFColor.BLACK.index);
style1.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);// 最好的設置Pattern
// 單元格背景的顯示模式.
style1.setFillForegroundColor(new HSSFColor.RED().getIndex()); // 設置單元格背景色;
style1.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平對齊方式
// style1.setWrapText(true);//文本區域隨內容多少自動調整
// style.setFillPattern(HSSFCellStyle.//);
// 設置字體Color,首先創建Font對象,后對font設置,然后做為參數傳給style
HSSFFont font = wb.createFont();
font.setColor(HSSFFont.SS_NONE);
// font.setFontHeightInPoints((short)24);
font.setFontName("Courier New");
// font.setItalic(true);
// font.setStrikeout(true);//給字體加上刪除線
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
style1.setFont(font);
/**
*
* 設置第零行表格說明行
*
*
*
*/
HSSFRow row1 = sheet.createRow((short) 1);
for (int j = 0; j < cellNum; j++) {
HSSFCell cell = row1.createCell((short) j);
cell.setCellValue((String) title.get(j));
cell.setCellStyle(style1);
}
// style.setFillPattern(HSSFCellStyle.NO_FILL);
/**
* 設置表的內容主體
*/
Iterator iter = list.iterator();
for (int i = 2; iter.hasNext(); i++) {
Department dep = (Department) iter.next();
HSSFRow row = sheet.createRow((short) i);
HSSFCell cell5 = row.createCell((short) 0);
HSSFCell cell1 = row.createCell((short) 1);
HSSFCell cell2 = row.createCell((short) 2);
HSSFCell cell3 = row.createCell((short) 3);
HSSFCell cell4 = row.createCell((short) 4);
cell5.setCellValue(dep.getId());
cell5.setCellStyle(style);
cell1.setCellValue(dep.getParentId());
cell1.setCellStyle(style);
cell2.setCellValue(dep.getName());
cell2.setCellStyle(style);
cell3.setCellValue(dep.getDescription());
cell3.setCellStyle(style);
cell4.setCellValue(dep.getImagePath());
cell4.setCellStyle(style);
}
// Write the output to a file}
// FileOutputStream fileOut = new
// FileOutputStream(args.getPath()+args.getFileName());
/**
* 對文件進行輸出操作。
*/
FileOutputStream fileOut = new FileOutputStream(args
.getPathAndName());
wb.write(fileOut);
// fileOut.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
}
}
mkdir /home/u1 創建文件夾/home/u1
chown oracle /home/u1 表示改變目錄所有者為oracle賬戶;
chgrp dba /home/u1 改變/home/u1目錄為dba所有;
chmod 755 /home/u1 表示oracle賬戶對/home/u1目錄有755權限;
rmdir /home/u1 表示刪除/home/u1目錄
hostname可以查看linux的計算機名;
whoami可以查看當前用戶;
pwd顯示當前路徑;
df查看系統的硬件信息
ls -lrt l表示顯示詳細列表,-t表示按時間排序,-r反向排序
cat orcl_ora_3436.trc|grep bucket
以下查看相關文件內容:
more /etc/oratab
cat /etc/passwd
cat /etc/group
copy命令
該命令的功能是將給出的文件或目錄拷貝到另一文件或目錄中,同MSDOS下的copy命令一樣,功能十分強大。
語法: cp [選項] 源文件或目錄 目標文件或目錄
說明:該命令把指定的源文件復制到目標文件或把多個源文件復制到目標目錄中。
該命令的各選項含義如下:
- a 該選項通常在拷貝目錄時使用。它保留鏈接、文件屬性,并遞歸地拷貝目錄,其作用等于dpR選項的組合。
- d 拷貝時保留鏈接。
- f 刪除已經存在的目標文件而不提示。
- i 和f選項相反,在覆蓋目標文件之前將給出提示要求用戶確認。回答y時目標文件將被覆蓋,是交互式拷貝。
- p 此時cp除復制源文件的內容外,還將把其修改時間和訪問權限也復制到新文件中。
- r 若給出的源文件是一目錄文件,此時cp將遞歸復制該目錄下所有的子目錄和文件。此時目標文件必須為一個目錄名。
- l 不作拷貝,只是鏈接文件。
需要說明的是,為防止用戶在不經意的情況下用cp命令破壞另一個文件,如用戶指定的目標文件名已存在,用cp命令拷貝文件后,這個文件就會被新源文件覆蓋,因此,建議用戶在使用cp命令拷貝文件時,最好使用i選項。
對于rownum來說它是oracle系統順序分配為從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,依此類推,這個偽字段可以用于限制查詢返回的總行數,而且rownum不能以任何表的名稱作為前綴。
舉例說明:
例如表:student(學生)表,表結構為:
ID char(6) --學號
name VARCHAR2(10) --姓名
create table student (ID char(6), name VARCHAR2(100));
insert into sale values('200001',‘張一’);
insert into sale values('200002',‘王二’);
insert into sale values('200003',‘李三’);
insert into sale values('200004',‘趙四’);
commit;
(1) rownum 對于等于某值的查詢條件
如 果希望找到學生表中第一條學生的信息,可以使用rownum=1作為條件。但是想找到學生表中第二條學生的信息,使用rownum=2結果查不到數據。因 為rownum都是從1開始,但是1以上的自然數在rownum做等于判斷是時認為都是false條件,所以無法查到rownum = n(n>1的自然數)。
SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回記錄條數的地方,保證不出錯,如:隱式游標)
SQL> select rownum,id,name from student where rownum=1;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200001 張一
SQL> select rownum,id,name from student where rownum =2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
(2)rownum對于大于某值的查詢條件
如果想找到從第二行記錄以后的記錄,當使用rownum>2是查不出記錄的,原因是由于rownum是一個總是從1開始的偽列,Oracle 認為rownum> n(n>1的自然數)這種條件依舊不成立,所以查不到記錄
SQL> select rownum,id,name from student where rownum >2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
那如何才能找到第二行以后的記錄呀。可以使用以下的子查詢方法來解決。注意子查詢中的rownum必須要有別名,否則還是不會查出記錄來,這是因為rownum不是某個表的列,如果不起別名的話,無法知道rownum是子查詢的列還是主查詢的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
NO ID NAME
---------- ------ ---------------------------------------------------
3 200003 李三
4 200004 趙四
SQL> select * from(select rownum,id,name from student)where rownum>2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
(3)rownum對于小于某值的查詢條件
如果想找到第三條記錄以前的記錄,當使用rownum<3是能得到兩條記錄的。顯然rownum對于rownum<n((n>1的自然數)的條件認為是成立的,所以可以找到記錄。
SQL> select rownum,id,name from student where rownum <3;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200001 張一
2 200002 王二
綜 上幾種情況,可能有時候需要查詢rownum在某區間的數據,那怎么辦呀從上可以看出rownum對小于某值的查詢條件是人為true的,rownum對 于大于某值的查詢條件直接認為是false的,但是可以間接的讓它轉為認為是true的。那就必須使用子查詢。例如要查詢rownum在第二行到第三行之 間的數據,包括第二行和第三行數據,那么我們只能寫以下語句,先讓它返回小于等于三的記錄行,然后在主查詢中判斷新的rownum的別名列大于等于二的記 錄行。但是這樣的操作會在大數據集中影響速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
NO ID NAME
---------- ------ ---------------------------------------------------
2 200002 王二
3 200003 李三
(4)rownum和排序
Oracle中的rownum的是在取數據的時候產生的序號,所以想對指定排序的數據去指定的rowmun行數據就必須注意了。
SQL> select rownum ,id,name from student order by name;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
3 200003 李三
2 200002 王二
1 200001 張一
4 200004 趙四
可以看出,rownum并不是按照name列來生成的序號。系統是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢
SQL> select rownum ,id,name from (select * from student order by name);
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200003 李三
2 200002 王二
3 200001 張一
4 200004 趙四
這樣就成了按name排序,并且用rownum標出正確序號(有小到大)
//ArrayList
{
ArrayList arraylist=new ArrayList();
arraylist.add(0,"end");//指定索引加入值
//需注意的是,如果現有2個值,我加入索引為5的那么就會出現異常
for(int i=0;i<2;i++){
arraylist.add(i,String.valueOf(i));
}
System.out.println("ArrayList:");
for(int i=0;i<arraylist.size();i++){
System.out.print(arraylist.get(i)+";");
}
arraylist.add("0");//直接加入值到ArrayList的最后
arraylist.add("0");
System.out.print("\nArrayList\'s lastIndexOf(\"0\") is "+arraylist.lastIndexOf("0"));
}
//Arrays
{
String []array=new String[]{"a","b","c"};
List list=Arrays.asList(array);
System.out.println("\nArrays:");
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+";");
}
System.out.print("\nArrays\'s length is "+array.length);//打印數組的長度
}
//Collections
{
String []array=new String[]{"a","b","c"};
List list=Arrays.asList(array);
Collections.fill(list,"Fill");//用Fill填充全部元素
System.out.println("\nCollections:");
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+";");
}
array=new String[]{"1","2","3"};
List list2=Arrays.asList(array);
Collections.copy(list,list2);//拷貝list2的數據進list
System.out.println("\n"+list);
Collections.swap(list,2,1);//調換索引為1和2的元素的位置
System.out.println(list);
}
//EventObject
{
String s="hello";
String s2=s;
EventObject eventobject=new EventObject(s);//一個準容器類型,確切的歸類它不是容器
System.out.println("EventObject:");
System.out.println(eventobject.getSource());
System.out.println(eventobject.equals(s2));
}
//HashMap
{
HashMap hashmap=new HashMap();//一個速度最快的容器
hashmap.put("0","c");
hashmap.put("1","a");
hashmap.put("2","b");
hashmap.put("3","a");
System.out.println("HashMap:");
System.out.println(hashmap);//該容器有其內部的排序方式
Set set=hashmap.keySet();//獲取全部鍵
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(hashmap.get(iterator.next())+";");
}
}
//HashSet
{
HashSet hashset=new HashSet();//一個絕對不能重復的類型
hashset.add("c");
hashset.add("b");
hashset.add("a");
hashset.add("a");
hashset.add("b");
System.out.println("\nHashSet:");
System.out.println(hashset);
Iterator iterator=hashset.iterator();//取出元素
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
}
//Hashtable
{
Hashtable hashtable=new Hashtable();//一個完全可以由其他容器替換的老容器類型
hashtable.put("0","c");
hashtable.put("1","a");
hashtable.put("3","c");
hashtable.put("2","b");
System.out.println("\nHashtable:");
Enumeration enumeration=hashtable.elements();//獲取元素,Enumeration已經不是主流,Iterator是它的下一代替代品
while(enumeration.hasMoreElements()){
System.out.print(enumeration.nextElement()+";");
}
}
//IdentityHashMap
{
IdentityHashMap identityhashmap=new IdentityHashMap();
identityhashmap.put("0","c");
identityhashmap.put("1","a");
identityhashmap.put("3","b");
identityhashmap.put("2","a");
System.out.println("\nIdentityHashMap:");
System.out.println(identityhashmap);
System.out.println(identityhashmap.containsKey("3"));//是否包含這個鍵
System.out.println(identityhashmap.containsValue("a"));//是否包含值
Set set=identityhashmap.entrySet();//傳為Set類型
System.out.println(set);
set=identityhashmap.keySet();//全部鍵
System.out.println(set);
}
//LinkedHashMap
{
LinkedHashMap linkedhashmap=new LinkedHashMap();
linkedhashmap.put("0","b");
linkedhashmap.put("2","a");
linkedhashmap.put("1","c");
linkedhashmap.put("3","b");
System.out.println("LinkedHashMap:");
System.out.println(linkedhashmap);
System.out.println(linkedhashmap.containsKey("2"));//是否包含這個鍵
System.out.println(linkedhashmap.containsValue("c"));//是否包含值
Set set=linkedhashmap.keySet();
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(linkedhashmap.get(iterator.next())+";");
}
}
//LinkedHashSet
{
LinkedHashSet linkedhashset=new LinkedHashSet();//它包含了幾種Set的屬性但卻沒有自己的特色
linkedhashset.add("c");
linkedhashset.add("a");
linkedhashset.add("a");
linkedhashset.add("b");
System.out.println("\nLinkedHashSet:");
System.out.println(linkedhashset);
System.out.println(linkedhashset.contains("a"));//是否包含對象
Iterator iterator=linkedhashset.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
}
//LinkedList
{
LinkedList linkedlist=new LinkedList();//自由使用是它的特色
linkedlist.add("a");
linkedlist.add(1,"c");
linkedlist.addLast("b");
linkedlist.addFirst("d");
System.out.println("\nLinkedList:");
System.out.println(linkedlist);
//linkedlist.clear();//該方法清空容器
//linkedlist.remove(0);//刪除索引為0的元素
//linkedlist.remove("d");//刪除值為d的元素
//linkedlist.removeFirst();//刪除第一個元素
//linkedlist.removeLast();//刪除最后一個元素
for(int i=0;i<linkedlist.size();i++){
System.out.print(linkedlist.get(i)+";");
}
}
//Stack
{
Stack stack=new Stack();//堆棧
stack.add("b");
stack.add(0,"c");
stack.push("d");
stack.add("e");
stack.push("a");
Enumeration enumeration=stack.elements();
System.out.println("\nStack:");
while(enumeration.hasMoreElements()){
System.out.print(enumeration.nextElement()+";");
}
//后進先出
System.out.println("\n"+stack.peek());
System.out.println(stack.pop());
System.out.println(stack.contains("d")+";"+stack.contains("a"));//是否包含該元素,有趣的事情發生了
System.out.println(stack.search("c"));//非常有用的屬性,檢索,但是由后向前的排列
}
//TreeMap
{
TreeMap treemap=new TreeMap();
treemap.put("0","d");
treemap.put("2","a");
treemap.put("1","b");
treemap.put("3","c");
System.out.println("\nTreeMap:");//可以對鍵排序
System.out.println(treemap);
System.out.println(treemap.firstKey());//返回第一個鍵
Set set=treemap.keySet();
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(treemap.get(iterator.next())+";");
}
}
//TreeSet
{
TreeSet treeset=new TreeSet();//自動排序內容
treeset.add("b");
treeset.add("a");
treeset.add("c");
treeset.add("d");
System.out.println("\nTreeSet:");
System.out.println(treeset);
System.out.println(treeset.first());//返回第一個元素
Iterator iterator=treeset.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
}
//Vector
{
Vector vector=new Vector();
vector.add(0,"b");
vector.add("a");
vector.addElement("d");
vector.add("c");
System.out.println("\nVector:");
System.out.println(vector);
vector.set(2,"h");//替換掉指定索引的元素
System.out.println(vector);
Object []str=vector.toArray();
for(int i=0;i<str.length;i++){
System.out.print(str[i]+";");
}
vector.setSize(2);//重新設置大小為2
System.out.println("\n"+vector);
}
//WeakHashMap
{
WeakHashMap weakhashmap=new WeakHashMap();
weakhashmap.put("1","b");
weakhashmap.put("2","c");
weakhashmap.put("0","d");
weakhashmap.put("3","a");
System.out.println("\nWeakHashMap:");
System.out.println(weakhashmap);
System.out.println(weakhashmap.containsKey("3"));//是否包含鍵
System.out.println(weakhashmap.containsValue("d"));//是否包含值
Set set=weakhashmap.entrySet();
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
//weakhashmap.remove("2");//刪除該鍵對應的值
//weakhashmap.get("1");//獲取指定鍵的值
}
}
在JAVA的util包中有兩個所有集合的父接口Collection和Map,它們的父子關系:
java.util
+Collection 這個接口extends自 --java.lang.Iterable接口
+List 接口
-ArrayList 類
-LinkedList 類
-Vector 類 此類是實現同步的
+Queue 接口
+不常用,在此不表.
+Set 接口
+SortedSet 接口
-TreeSet 類
-HashSet
+Map 接口
-HashMap 類 (除了不同步和允許使用 null 鍵/值之外,與 Hashtable 大致相同.)
-Hashtable 類 此類是實現同步的,不允許使用 null 鍵值
+SortedMap 接口
-TreeMap 類
以下對眾多接口和類的簡單說明:首先不能不先說一下數組(Array)
一、Array , Arrays
Java所有“存儲及隨機訪問一連串對象”的做法,array是最有效率的一種。
1、
效率高,但容量固定且無法動態改變。
array還有一個缺點是,無法判斷其中實際存有多少元素,length只是告訴我們array的容量。
2、Java中有一個Arrays類,專門用來操作array。
arrays中擁有一組static函數,
equals():比較兩個array是否相等。array擁有相同元素個數,且所有對應元素兩兩相等。
fill():將值填入array中。
sort():用來對array進行排序。
binarySearch():在排好序的array中尋找元素。
System.arraycopy():array的復制。
二、Collection , Map
若撰寫程序時不知道究竟需要多少對象,需要在空間不足時自動擴增容量,則需要使用容器類庫,array不適用。
1、Collection 和 Map 的區別
容器內每個為之所存儲的元素個數不同。
Collection類型者,每個位置只有一個元素。
Map類型者,持有 key-value pair,像個小型數據庫。
2、Java2容器類類庫的用途是“保存對象”,它分為兩類,各自旗下的子類關系
Collection
--List:將以特定次序存儲元素。所以取出來的順序可能和放入順序不同。
--ArrayList / LinkedList / Vector
--Set : 不能含有重復的元素
--HashSet /TreeSet
Map
--HashMap
--HashTable
--TreeMap
Map----一組成對的“鍵值對”對象,即其元素是成對的對象,最典型的應用就是數據字典,并且還有其它廣泛的應用。另外,Map可以返回其所有鍵組成的Set和其所有值組成的Collection,或其鍵值對組成的Set,并且還可以像數組一樣擴展多維Map,只要讓Map中鍵值對的每個“值”是一個Map即可。
Collection下 1.迭代器
迭代器是一種設計模式,它是一個對象,它可以遍歷并選擇序列中的對象,而開發人員不需要了解該序列的底層結構。迭代器通常被稱為“輕量級”對象,因為創建它的代價小。
Java中的Iterator功能比較簡單,并且只能單向移動:
(1) 使用方法iterator()要求容器返回一個Iterator。第一次調用Iterator的next()方法時,它返回序列的第一個元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。
(2) 使用next()獲得序列中的下一個元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡單的實現,為List設計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。
2.List的功能方法
List(interface): 次序是List最重要的特點;它確保維護元素特定的順序。List為Collection添加了許多方法,使得能夠向List中間插入與移除元素(只推薦LinkedList使用)。一個List可以生成ListIterator,使用它可以從兩個方向遍歷List,也可以從List中間插入和刪除元素。
ArrayList: 由數組實現的List。它允許對元素進行快速隨機訪問,但是向List中間插入與移除元素的速度很慢。ListIterator只應該用來由后向前遍歷ArrayList,而不是用來插入和刪除元素,因為這比LinkedList開銷要大很多。
LinkedList: 由列表實現的List。對順序訪問進行了優化,向List中間插入與刪除得開銷不大,隨機訪問則相對較慢(可用ArrayList代替)。它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),這些方法(沒有在任何接口或基類中定義過)使得LinkedList可以當作堆棧、隊列和雙向隊列使用。
3.Set的功能方法
Set(interface): 存入Set的每個元素必須是唯一的,這也是與List不同的,因為Set不保存重復元素。加入Set的Object必須定義equals()方法以確保對象的唯一性。Set與Collection有完全一樣的接口。Set接口不保證維護元素的次序。
HashSet: HashSet能快速定位一個元素,存入HashSet的對象必須定義hashCode()。
TreeSet: 保持次序的Set,底層為樹結構。使用它可以從Set中提取有序的序列。
LinkedHashSet: 具有HashSet的查詢速度,且內部使用鏈表維護元素的順序(插入的次序)。于是在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。
HashSet采用散列函數對元素進行排序,這是專門為快速查詢而設計的;TreeSet采用紅黑樹的數據結構進行排序元素;LinkedHashSet內部使用散列以加快查詢速度,同時使用鏈表維護元素的次序,使得看起來元素是以插入的順序保存的。需要注意的是,生成自己的類時,Set需要維護元素的存儲順序,因此要實現Comparable接口并定義compareTo()方法。
3、其他特征
* List,Set,Map將持有對象一律視為Object型別。
* Collection、List、Set、Map都是接口,不能實例化。
繼承自它們的 ArrayList, Vector, HashTable, HashMap是具象class,這些才可被實例化。
* vector容器確切知道它所持有的對象隸屬什么型別。vector不進行邊界檢查。
三、Collections
Collections是針對集合類的一個幫助類。提供了一系列靜態方法實現對各種集合的搜索、排序、線程完全化等操作。
相當于對Array進行類似操作的類——Arrays。
如,Collections.max(Collection coll); 取coll中最大的元素。
Collections.sort(List list); 對list中元素排序
四、如何選擇?
1、容器類和Array的區別、擇取
* 容器類僅能持有對象引用(指向對象的指針),而不是將對象信息copy一份至數列某位置。
* 一旦將對象置入容器內,便損失了該對象的型別信息。
2、
* 在各種Lists中,最好的做法是以ArrayList作為缺省選擇。當插入、刪除頻繁時,使用LinkedList();
Vector總是比ArrayList慢,所以要盡量避免使用。
* 在各種Sets中,HashSet通常優于HashTree(插入、查找)。只有當需要產生一個經過排序的序列,才用TreeSet。
HashTree存在的唯一理由:能夠維護其內元素的排序狀態。
* 在各種Maps中
HashMap用于快速查找。
* 當元素個數固定,用Array,因為Array效率是最高的。
結論:最常用的是ArrayList,HashSet,HashMap,Array。而且,我們也會發現一個規律,用TreeXXX都是排序的。
注意:
1、Collection沒有get()方法來取得某個元素。只能通過iterator()遍歷元素。
2、Set和Collection擁有一模一樣的接口。
3、List,可以通過get()方法來一次取出一個元素。使用數字來選擇一堆對象中的一個,get(0)...。(add/get)
4、一般使用ArrayList。用LinkedList構造堆棧stack、隊列queue。
5、Map用 put(k,v) / get(k),還可以使用containsKey()/containsValue()來檢查其中是否含有某個key/value。
HashMap會利用對象的hashCode來快速找到key。
* hashing
哈希碼就是將對象的信息經過一些轉變形成一個獨一無二的int值,這個值存儲在一個array中。
我們都知道所有存儲結構中,array查找速度是最快的。所以,可以加速查找。
發生碰撞時,讓array指向多個values。即,數組每個位置上又生成一個梿表。
6、Map中元素,可以將key序列、value序列單獨抽取出來。
使用keySet()抽取key序列,將map中的所有keys生成一個Set。
使用values()抽取value序列,將map中的所有values生成一個Collection。
為什么一個生成Set,一個生成Collection?那是因為,key總是獨一無二的,value允許重復。
1、項目經理必須關注項目成功的三個標準
簡單地說,一是準時;二是預算控制在既定的范圍內;三是質量得到經理和用戶們的贊許。項目經理必須保證項目小組的每一位成員都能對照上面三個標準來進行工作。
2、任何事都應當先規劃再執行
就項目管理而言,很多專家和實踐人員都同意這樣一個觀點:需要項目經理投入的最重要的一件事就是規劃。只有詳細而系統的由項目小組成員參與的規劃才是項目成功的唯一基礎。當現實的世界出現了一種不適于計劃生存的環境時,項目經理應制定一個新的計劃來反映環境的變化。規劃、規劃、再規劃就是項目經理的一種生活方式。
3、項目經理必須以自己的實際行動向項目小組成員傳遞一種緊迫感
由于項目在時間、資源和經費上都是有限的,項目最終必須完成。但項目小組成員大多有自己的愛好,項目經理應讓項目小組成員始終關注項目的目標和截止期限。例如,可以定期檢查,可以召開例會,可以制作一些提醒的標志置于項目的場所。
4、成功的項目應使用一種可以度量且被證實的項目生命周期
標準的信息系統開發模型可以保證專業標準和成功的經驗能夠融入項目計劃。這類模型不僅可以保證質量,還可以使重復勞動降到最低程度。因此,當遇到時間和預算壓力需要削減項目時,項目經理應確定一種最佳的項目生命周期。
5、所有項目目標和項目活動必須生動形象地得以交流和溝通
項目經理和項目小組在項目開始時就應當形象化地描述項目的最終目標,以確保與項目有關的每一個人都能記住。項目成本的各個細節都應當清楚、明確、毫不含糊,并確保每個人對此都達成了一致的意見。
6、采用漸進的方式逐步實現目標
如果試圖同時完成所有的項目目標,只會造成重復勞動,既浪費時間又浪費錢。俗話說,一口吃不成個胖子。項目目標只能一點一點地去實現,并且每實現一個目標就進行一次評估,確保整個項目能得以控制。
7、項目應得到明確的許可,并由投資方簽字實施
在實現項目目標的過程中獲得明確的許可是非常重要的。應將投資方的簽字批準視為項目的一個出發點。道理很簡單:任何有權拒絕或有權修改項目目標的人都應當在項目啟動時審查和批準這些項目目標。
8、要想獲得項目成功必須對項目目標進行透徹的分析
研究表明,如果按照眾所周知記錄在案的業務需求來設計項目的目標,則該項目多半會成功。所以,項目經理應當堅持這樣一個原則,即在組織機構啟動項目之前,就應當為該項目在業務需求中找到充分的依據。
9、項目經理應當責權對等
項目經理應當對項目的結果負責,這一點并不過分。但與此相對應,項目經理也應被授予足夠的權利以承擔相應的責任。在某些時候,權利顯得特別重要,如獲取或協調資源,要求得到有關的中小企業的配合,做相應的對項目成功有價值的決策等等。
10、項目投資方和用戶應當主動介入,不能被動地坐享其成
多數項目投資方和用戶都能正確地要求和行使批準(全部或部分)項目目標的權力。但伴隨這個權力的是相應的責任——主動地介入項目的各個階段。例如,在項目早期要幫助確定項目目標;在項目進行中,要對完成的階段性目標進行評估,以確保項目能順利進行。項目投資方應幫助項目經理去訪問有關的中小企業和目標顧客的成員,并幫助項目經理獲得必要的文件資料。
11、項目的實施應當采用市場運作機制
在多數情況下,項目經理應將自己看成是賣主,以督促自己完成投資方和用戶交付的任務。項目計劃一旦批準項目經理應當定期提醒項目小組成員該項目必須滿足的業務需求是什么,以及該怎樣工作才能滿足這些業務需求。
12、項目經理應當獲得項目小組成員的最佳人選
最佳人選是指受過相應的技能培訓,有經驗,素質高。對于項目來說,獲得最佳人選往往能彌補時間、經費或其它方面的不足。項目經理應當為這些最佳的項目成員創造良好的工作環境,如幫助他們免受外部干擾,幫助他們獲得必要的工具和條件以發揮他們的才能。
在開始正文之前,我想先講兩個故事——關于軟件項目的故事。
故事一
有兩個軟件項目(姑且稱之為“項目 A”和“項目 B”),它們在開始時的預算都是 50 個人月,時間是 5 個月。
項目 A 在 5 個月后完工,耗費成本 50 人月
項目 B 在 6 個月后完工,耗費成本 70 人月
在軟件圈子里摸爬滾打多年的讀者們對這個故事一定有自己的判斷——而且我可以大致猜出是什么樣的判斷。不過先別著急,我們還有另一個故事。
故事二
有兩個軟件項目(仍然姑且稱之為“項目 A”和“項目 B”),它們在開始時的計劃都是交付 200 項功能。
項目 A 在項目結束時一次性交付了最初計劃的 200 項功能,但客戶發現其中大約 30 項功能沒有太大用處,而另外 30 項有用的功能要等到下一個項目才能實現。
項目 B 在第一個月結束時交付了第一個版本,此后每兩周交付一個新的版本。在項目進行的過程中,客戶進行了一次業務調整,加入了 90 項新的功能,并擱置了 50 項用處不大的功能。最終該項目交付了 240 項功能。
聰明的讀者大概注意到了,前后兩個故事講的是同一回事,同樣的兩個項目。現在我的問題來了:請問哪個項目是更成功的項目?
這個問題并不容易回答——實際上它沒有標準答案。站在很多軟件企業的立場上,項目 A 是一個理想的成功項目:按時間、按成本完成預先約定的任務。請注意,我用了“理想的”這個詞,稍后我還會解釋這個有趣的詞,因為實際上的軟件項目往往沒有那么理想。
而如果換一個角度,站在客戶的立場上呢?也許付錢購買軟件的客戶會有一些不同的想法。項目 B 從開始之后一個月便交付了第一個可工作的版本,從那時起客戶就開始使用這個軟件的部分功能,并且不斷地把自己使用的感受反饋給開發團隊。在真實的業務運營過程中,客戶甚至發現了一種新的盈利模式,并進行了一次大規模的業務調整,這次調整的結果也直觀地體現在軟件項目中。雖然項目B的整體交付速率低于項目 A,但它提供的所有功能都是客戶真正需要的,它們為客戶提供實實在在的價值——更不用說,客戶提前好幾個月就開始使用這個軟件。
實際上,這是一篇關于軟件價值的文章。和“成功項目”一樣,對于“軟件的價值”,不同的人也會有不同的定義。不過作為付錢購買軟件的客戶,他對于軟件價值的定義是一目了然的:他能夠從使用軟件中創造多少價值,軟件能夠為他的業務提供多少價值,這就是軟件的價值。或者說得更簡明一點:
軟件價值源自使用
這正是為什么很多客戶青睞“項目 B”的原因——我并不打算聲稱所有客戶都有同樣的觀點,稍后我也會舉出反例,但至少支持這一觀點的客戶不在少數。因為他們處在一個殘酷而快速變化的商業環境中:他們的供應商在變化,他們的客戶在變化,他們所處的經濟環境和政策環境也在變化。這一切的變化迫使他們的業務也要隨之變化。更要命的是,今天這個經濟全球化的時代是一個“快魚吃慢魚”的時代,客戶迫切希望新的軟件系統為他們帶來競爭優勢——哪怕這個軟件系統尚未完成,只要能夠投入使用。最后,客戶對于新的軟件系統究竟應該是什么樣子并沒有百分之百的把握,他們的想法往往要在真正使用軟件之后才會浮現成型。幾方面的因素加在一起,使得這些客戶更愿意盡快開始使用軟件、提出反饋、并不斷完善軟件,而不是提出一組需求、然后坐等幾個月之后原封不動地拿到這些功能。
一個真實的案例
在 ThoughtWorks 的一個項目中,開發者們在項目開始之后一個月內就發布了第一個版本——只有一些簡單的數據采集功能。在發布展示會上,發生了這樣的對話……
開發者:這是我們的第一個功能。我們從文本文件、Excel 數據表和遺留數據庫采集數據,現在我們的數據庫中有這些數據……(展示數據庫結構)
客戶:唔……有意思。要是你能做這樣一個查詢(寫出查詢要求),得到的結果可能會有用。
開發者:可是我們的界面上沒有地方做這樣的查詢操作。
客戶:啊,我不需要操作界面,只要每天深夜做一次查詢,把報表發到我的信箱就可以了。
開發者:這樣嗎……另一個問題是,這需要花我們幾天時間。
客戶:不要緊,把別的任務往后放幾天好了,我很想看到這份報表。
開發者:那好吧,下周我們就會開始提供這個報表。
猜猜結果怎么樣?一周之后客戶就開始每天接收這份報表,并根據報表內容做一些分析和決策。僅僅幾個月之后,這份報表給客戶帶來的收益就已經超過了整個項目的投資——這時項目其他部分的開發甚至還沒有完成。
想想這個客戶會怎么定義一個“成功的軟件項目”?好吧,也許這個項目超過了預期的時間,也許投入了更多的人力,但這些并不意味著“項目失敗”——只是付出更高的成本。關鍵在于,他投入的這些成本能夠帶來多大的收益,他的投資回報率是否劃算。對于這個客戶而言,如果項目能夠隨時給他提供可用的、能夠創造最大價值的軟件,能夠隨時讓——就像故事中提到的——這種有價值的想法得以實現,這就是一個成功的項目。
所以,親愛的讀者,請你忘記本文標題上出現的“敏捷”二字,我們在這里所說的不是別的,就是一種為客戶創造最大化價值的軟件開發方法。這樣的方法有很多種,但它們有一個共同的特點:盡快、盡可能頻繁地交付可以工作的軟件,讓客戶盡快開始使用軟件,從使用中創造價值、厘清思路、提出反饋。仍然以 ThoughtWorks 的項目為例,這些項目通常在啟動開發階段之后一個月內就會發布第一個版本,隨后每一周或每兩周發布一個新版本——每個版本都是一個可以工作的軟件,每個版本都比前一個版本具有更豐富的功能,并且每個版本都包含客戶認為迄今為止最有價值的那些功能。用軟件開發的“黑話”,“開發下一個版本”的過程叫做“迭代”,這些開發方法最大的共同點就是“迭代式開發”——不是一股腦地交付全部功能,而是每次增加一點、漸進地交付最有價值的功能。
軟件開發的夢想與真實
回到文章開始處的兩個故事。我曾經說過,對于很多軟件企業而言,項目 A 是一個“理想的”成功項目。那么,是什么讓情況變得不那么理想?
答案是一個所有軟件開發者耳熟能詳的詞:需求變更。在真實的項目中,客戶通常不會等到最后一天再照單全收整個項目,因為他知道自己的業務正在發生變化。這時需求變更就出現了,伴隨著來回的扯皮和討價還價。更糟的是,大量的需求變更發生在項目晚期——因為直到這時客戶才真正看到、使用到這個軟件,他的很多想法才真正浮現成型。隨著這種“最后一分鐘的需求變更”,項目超期、超出預算也就成了家常便飯。能夠像項目A這樣完工交付的,實在是鳳毛麟角的幸運兒。
為了對付需求變更這個噩夢,軟件開發者們還發明了另一個詞:變更控制。這個有趣的詞暗示著:需求變更是一種“不好”的東西,是需要“控制”的東西。然而站在客戶的角度上想想,他在親身使用了軟件之后提出的要求,難道不是最有價值的東西嗎?把這種真正創造業務價值的要求“控制”起來,難道是合理的嗎?
在前面我也暗示過,并非所有的客戶都一定青睞迭代式開發。那么,哪些軟件項目不一定需要迭代式開發呢?從整篇文章的內容不難看出,如果客戶的業務絕對不會變化,如果客戶的需求巨細靡遺非常明確,如果客戶不需要盡快開始使用軟件以便收回成本,那么迭代式開發對他的幫助就會小得多。不過,如果讀者認真思考的話,這樣的例子也許并不多——也許比你最初認為的要少得多。一個很好的例子是“神州六號”火箭使用的計算機控制系統。還有多少這樣的例子?讀者不妨試著自己想想。
如果我足夠幸運的話,也許一些讀者已經被這篇文章吊起了胃口:既然有這么好的軟件開發方法,既然它能夠為我們創造更大的價值,那還等什么呢,我們馬上就動手吧。事情不會那么簡單。為了讓迭代式開發能夠成為現實,為了確保盡快、盡可能頻繁地交付,為了確保每次交付的都是最有價值的功能,我們——包括軟件開發者、軟件企業和客戶——需要很多的改變。這里既有職責與權利的劃分,也有開發過程和團隊的重組,還有技術層面的實踐指導。這些正是敏捷方法學所涵蓋的內容。缺少了這些東西,“為客戶創造最大價值”就只能成為一句空話。在后續的文章里,我們將結合 ThoughtWorks 的實踐經驗,逐步介紹敏捷方法的方方面面。
最開始時微軟公司將Java當做一種能解決C和C++中存在的問題的語言,并不在意,并繼續維持和培訓著其C和C++技術和編程人員。接下來不幸的是,正當微軟盡力在Visual J++基礎上拓展Java功能,并使之與Windows操作系統緊密結合在一起的時候,Sun公司對微軟提出法律訴訟說其違反了許可證協議中的條款,最終的結果是微軟公司不得不停止其Visual J++產品的開發。(微軟公司仍然銷售Visual J++,但是從1998年10月以來就沒有新的版本發布,并且在.Net平臺上也沒有Visual J++的位置了)接下來的事情就很清楚了,微軟公司開發了C#語言。接下來的一部分將討論C#與Java的相似性。
C#與Java的區別
C#最引人的地方是它與Java的區別而不是其相似性。下面主要來介紹C#區別于Java的不同的運行特點及Java完全沒有的特點。
中間語言
當MSIL被編譯成最終的機器碼時,微軟公司在如何選擇上是非常靈活的。微軟公司很謹慎的對外宣稱說MSIL不是解釋型的,而是被編譯成機器碼。因為開發人員都有這樣一個觀念:Java程序天生就比C程序運行慢,所以這暗示著基于MSIL的程序優于解釋型的Java字節碼。當然,既然C#和其它MSIL產品編譯器還未發布,那么這一點就還未證明,但是Java無處不在的即時編譯器使得C#和Java在效能上是一樣的。象“C#是編譯型的,Java是解釋型的”這樣話只是銷售中的技巧。Java的字節碼和MSIL碼都是的類似匯編的中間語言,在運行時執行這些中間碼。
與COM的整合
對于基于Windows的C#開發人員來說,最大的收獲是對COM的無損整合,COM是微軟Win32的組件技術。實際上,任何一種.Net體系結構上的語言最終都可能去寫COM的客戶端和服務器端程序。用C#編寫的類也會作為COM組件的子類;結果類(resulting class)也能作為COM組件使用,并作為COM組件的子類。
微軟公司的目標是使越來越多的語言都能訪問組件,并使這些組件能整合到.Net體系結構中。已有幾個廠商開始著手開發支持.Net功能的編程語言,如COBOL和Haskell。開發人員能選擇不同的語言解決不同問題,更重要的是,開發人員不必為采用.Net體系結構而必須學習新語言,可以選擇一種他們熟悉的語言。
總結
本文的第一、二部分對C#做了一膚淺的總體介紹,主要是其產生動機及與Java的相似性。第三部分則涵概了C#的語言特點。用范例說明了C#與Java兩者在相似性外,它們又是非常不同的,有許多細微的語義和設計區別,適合不同的技術和市場環境,又談到了微軟公司對C#進行標準化方面的嘗試,及其對Java的影響。
c#與java的區別
1.屬性:
java中定義和訪問均要用get和set方法,可以不成對出現。
c#中是真正的屬性,定義時get和set必須同時出現,房問時用.號即可。不用get,set
2.對象索引
就是對象數組
public Story this [int index] {
3.C#中,不用任何范圍修飾符時,默認的是protect,因而不能在類外被訪問.
4.因為JAVA規定,在一個文件中只能有一個public類,而且這個類的名稱必須與文件名一模一樣,這是一個區別
5.在C#中,它是以Main方法來定位入口的.如果一個程序中沒有一個名為Main的方法,就會出"找不到入口的錯誤".不要把Main寫成main喲
6.C#預定義的簡單數據類型比Java多。例如,C#有unit,即無符號整數
7.忘掉Java中的static final修飾符。在C#中,常量可以用const關鍵詞聲明
C#的設計者還增加了readonly關鍵詞,readonly域只能通過初始化器或類的構造函數設置
8.公用類的入口點:c#是可以對Main進行重載(java中是main),允許有int返回值和空參數的Main
9.在Java中,switch語句只能處理整數。但C#中的switch語句不同,它還能夠處理字符變量。請考慮下面用switch語句處理字符串變量的C#代碼
10.C#沒有>>>移位操作符
11.goto關鍵詞:
Java不用goto關鍵詞。在C#中,goto允許你轉到指定的標簽。不過,C#以特別謹慎的態度對待goto,比如它不允許goto轉入到語句塊的內部。在Java中,你可以用帶標簽的語句加上break或continue取代C#中的goto。
12.int[] x = { 0, 1, 2, 3 };
int x[] = { 0, 1, 2, 3 };
但在C#中,只有第一行代碼合法,[]不能放到變量名字之后。
13.與Java不同的是,C#允許為名稱空間或者名稱空間中的類指定別名:
using TheConsole = System.Console;
14.在Java中,包的名字同時也是實際存在的實體,它決定了放置.java文件的目錄結構。在C#中,物理的包和邏輯的名稱之間是完全分離的
.NET中包的實體稱為程序集(Assembly)。每一個程序集包含一個manifest結構。manifest列舉程序集所包含的文件,控制哪些類型和資源被顯露到程序集之外,并把對這些類型和資源的引用映射到包含這些類型與資源的文件。程序集是自包含的,一個程序集可以放置到單一的文件之內,也可以分割成多個文件。.NET的這種封裝機制解決了DLL文件所面臨的問題,即臭名昭著的DLL Hell問題。
15.在Java中,java.lang包是默認的包,C#中不存在默認的包
16.C#中的訪問修飾符與Java中的基本對應,但多出了一個internal。簡而言之,C#有5種類型的可訪問性,如下所示:
public:成員可以從任何代碼訪問。
protected:成員只能從派生類訪問。
internal:成員只能從同一程序集的內部訪問。
protected internal:成員只能從同一程序集內的派生類訪問。
private:成員只能在當前類的內部訪問。
17.由于C#中不存在final關鍵詞,如果想要某個類不再被派生,你可以使用sealed關鍵詞
18.與Java不同,C#中的接口不能包含域(Field)。
另外還要注意,在C#中,接口內的所有方法默認都是公用方法。在Java中,方法聲明可以帶有public修飾符(即使這并非必要),但在C#中,顯式為接口的方法指定public修飾符是非法的。例如,下面的C#接口將產生一個編譯錯誤。
19.C#中的is操作符與Java中的instanceof操作符一樣,兩者都可以用來測試某個對象的實例是否屬于特定的類型。在Java中沒有與C#中的as操作符等價的操作符。as操作符與is操作符非常相似,但它更富有“進取心”:如果類型正確的話,as操作符會嘗試把被測試的對象引用轉換成目標類型;否則,它把變量引用設置成null。
20.C#仍舊保留了C++的內存手工管理方法,它適合在速度極端重要的場合使用,而在Java中這是不允許的
21.在C#中,所有的異常都從一個名為Exception的類派生
22.枚舉器即enum類型(java無),把它作為一個變量值的類型使用,從而把變量可能的取值范圍限制為枚舉器中出現的值。
23.結構(Struct)與類很相似,而結構是一種值類型,它存儲在棧中或者是嵌入式的,結構可以實現接口,可以象類一樣擁有成員,但結構不支持繼承
24.屬性聲明語法的第一部分與域聲明很相似,第二部分包括一個set過程和/或一個get過程
25.傳值方式:
在java中簡單數據類型的值傳參時,都以傳值方式;
在c#中如果加ref則會以引用的方式傳值(方法內部改變該參數,則外部變量一起跟著變);
加out與ref基本相同,但out不要求參數一定要初始化.
26.c#保留了指針。unsafe
27.代理:代理(delegate)可以看作C++或者其他語言中的函數指針
代理用來封裝可調用方法。你可以在類里面編寫方法并在該方法上創建代理,此后這個代理就可以被傳遞到第二個方法。這樣,第二個方法就可以調用第一個方法。
代理是從公共基類System.Delegate派生的引用類型。定義和使用代理包括三個步驟:聲明,創建實例,調用。代理用delegate聲明語法聲明。
初學 Java 有段時間了,感覺似乎開始入了門,有了點兒感覺
但是發現很多困惑和疑問而且均來自于最基礎的知識
折騰了一陣子又查了查書,終于對 String 這個特殊的對象有了點感悟
大家先來看看一段奇怪的程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
這個程序真是簡單啊!可是有什么問題呢?
1. 來自 String 的憂慮
上面這段程序中,到底有幾個對象呢?
可能很多人脫口而出:兩個,s1 和 s2
為什么?
String 是 final 類,它的值不可變。
看起來似乎很有道理,那么來檢測一下吧,稍微改動一下程序
就可以看到結果了:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
呵呵,很多人都會說已經不止兩個對象了
編譯并運行程序,輸出:s1 == s2
啊!
為什么 s1 == s2 ?
== 分明是在說:s1 與 s2 引用同一個 String 對象 -- "Monday"!
2. 千變萬化的 String
再稍微改動一下程序,會有更奇怪的發現:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
我們將 s2 用 new 操作符創建
程序輸出:
s1 != s2
s1 equals s2
嗯,很明顯嘛
s1 s2分別引用了兩個"Monday"String對象
可是為什么兩段程序不一樣呢?
3. 在 String 的游泳池中游泳
哈哈,翻了翻書終于找到了答案:
原來,程序在運行的時候會創建一個字符串緩沖池
當使用 s2 = "Monday" 這樣的表達是創建字符串的時候,程序首先會
在這個String緩沖池中尋找相同值的對象,在第一個程序中,s1先被
放到了池中,所以在s2被創建的時候,程序找到了具有相同值的 s1
將 s2 引用 s1 所引用的對象"Monday"
第二段程序中,使用了 new 操作符,他明白的告訴程序:
“我要一個新的!不要舊的!”與是一個新的"Monday"Sting對象被創
建在內存中。他們的值相同,但是位置不同,一個在池中游泳
一個在岸邊休息。哎呀,真是資源浪費,明明是一樣的非要分開做什么呢?
4. 繼續潛水
再次更改程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
這次加入:s2 = s2.intern();
哇!程序輸出:
s1 == s2
s1 equals s2
原來,程序新建了 s2 之后,又用intern()把他打翻在了池里
哈哈,這次 s2 和 s1 有引用了同樣的對象了
我們成功的減少了內存的占用
5. == 與 equals() 的爭斗
String 是個對象,要對比兩個不同的String對象的值是否相同
明顯的要用到 equals() 這個方法
可是如果程序里面有那么多的String對象,有那么多次的要用到 equals ,
哦,天哪,真慢啊
更好的辦法:
把所有的String都intern()到緩沖池去吧
最好在用到new的時候就進行這個操作
String s2 = new String("Monday").intern();
嗯,大家都在水池里泡著了嗎?哈哈
現在我可以無所顧忌的用 == 來比較 String 對象的值了
真是爽啊,又快又方便!
關于String :)
String 啊 String ,讓我說你什么好呢?
你為我們 Java 程序員帶來所有的困擾還不夠嗎?
看看 String 這一次又怎么鬧事兒吧
1. 回顧一下壞脾氣的 String 老弟
例程1:
class Str {
public static void main(String[] args) {
String s = "Hi!";
String t = "Hi!";
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
程序輸出什么呢?
如果看客們看過我的《來自 String 的困惑》之一
相信你很快會做出正確的判斷:
程序輸出:equals
2. 哦,天哪,它又在攪混水了
例程2:
class Str {
public static void main(String[] args) {
String s = "HELLO";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
那么這個程序有輸出什么呢?
慎重!再慎重!不要被 String 這個迷亂的家伙所迷惑!
它輸出:equals
WHY!!!
把程序簡單的更改一下:
class Str2 {
public static void main(String[] args) {
String s = "Hello";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
你可能會說:不是一樣嗎?
不!千真萬確的,不一樣!這一次輸出:not equals
Oh MyGOD!!!
誰來教訓一下這個 String 啊!
3. 你了解你的馬嗎?
“要馴服脫韁的野馬,就要了解它的秉性”牛仔們說道。
你了解 String 嗎?
解讀 String 的 API ,可以看到:
toUpperCase() 和 toLowerCase() 方法返回一個新的String對象,
它將原字符串表示字符串的大寫或小寫形勢;
但是要注意:如果原字符串本身就是大寫形式或小寫形式,那么返回原始對象。
這就是為什么第二個程序中 s 和 t 糾纏不清的緣故
對待這個淘氣的、屢教不改的 String ,似乎沒有更好的辦法了
讓我們解剖它,看看它到底有什么結構吧:
(1) charAt(int n) 返回字符串內n位置的字符,第一個字符位置為0,
最后一個字符的位置為length()-1,訪問錯誤的位置會扔出一塊大磚頭:
StringIndexOutOfBoundsException 真夠大的
(2) concat(String str) 在原對象之后連接一個 str ,但是返回一個新的 String 對象
(3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法
這個方法的實質是首先調用靜態字符方法toUpperCase() 或者 toLowerCase()
將對比的兩個字符轉換,然后進行 == 運算
(4) trim() 返回一個新的對象,它將原對象的開頭和結尾的空白字符切掉
同樣的,如果結果與原對象沒有差別,則返回原對象
(5) toString() String 類也有 toString() 方法嗎?
真是一個有趣的問題,可是如果沒有它,你的 String 對象說不定真的不能用在
System.out.println() 里面啊
小心,它返回對象自己
String 類還有很多其他方法,掌握他們會帶來很多方便
也會有很多困惑,所以堅持原則,是最關鍵的
4. 我想買一匹更好的馬
來購買更馴服溫和的 String 的小弟 StringBuffer 吧
這時候會有人反對:它很好用,它效率很高,它怎么能夠是小弟呢?
很簡單,它的交互功能要比 String 少,如果你要編輯字符串
它并不方便,你會對它失望
但這不意味著它不強大
public final class String implements Serializable, Comparable, CharSequence
public final class StringBuffer implements Serializable, CharSequence
很明顯的,小弟少了一些東東,不過這不會干擾它的前途
StringBuffer 不是由 String 繼承來的
不過要注意兄弟它也是 final 啊,本是同根生
看看他的方法吧,這么多穩定可靠的方法,用起來比頑皮的 String 要有效率的多
?br /> Java 為需要改變的字符串對象提供了獨立的 StringBuffer 類
它的實例不可變(final),之所以要把他們分開
是因為,字符串的修改要求系統的開銷量增大,
占用更多的空間也更復雜,相信當有10000人擠在一個狹小的游泳池里游泳
而岸邊又有10000人等待進入游泳池而焦急上火
又有10000人在旁邊看熱鬧的時候,你這個 String 游泳池的管理員也會焦頭爛額
在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了,
而當要頻繁的更改字符串的內容的時候,就要借助于宰相肚里能撐船的
StringBuffer 了
5. 宰相肚里能撐船
(1) length() 與 capacity()
String 中的 length() 返回字符串的長度
兄弟 StringBuffer 也是如此,他們都由對象包含的字符長度決定
capacity()呢?
public class TestCapacity {
public static void main(String[] args){
StringBuffer buf = new StringBuffer("it was the age of wisdom,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
String str = buf.toString();
System.out.println("str = " + str);
System.out.println("str.length() = " + str.length());
buf.append(" " + str.substring(0,18)).append("foolishness,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
System.out.println("str = " + str);
}
}
程序輸出:
buf = it was the age of wisdom.
buf.length() = 25
buf.capacity() = 41
str = it was the age of wisdom
str.length() = 25
buf = it was the age of wisdom, it was the age of foolishness,
buf.length() = 56
buf.capacity() = 84
str = it was the age of wisdom,
可以看到,在內容更改之后,capacity也隨之改變了
長度隨著向字符串添加字符而增加
而容量只是在新的長度超過了現在的容量之后才增加
StringBuffer 的容量在操作系統需要的時候是自動改變的
程序員們對capacity所能夠做的僅僅是可以在初始化 StringBuffer對象的時候
以上片斷引用自http://bbs.blueidea.com/viewthread.php?tid=945875&page=###
解釋得比較形象和經典。具體的比較,要親自動手運行一下程序才行,如下為網上找到的專門研究equals和==的關系的程序,相信可從中體會出他們的深刻不同:
String s1 = null;
String s2 = null;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
s1 = s2;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
System.out.println("***1***");
s1 = null;
s2 = "";
System.out.println(s1==s2);//false
//System.out.println(s1.equals(s2));//NullPointerException
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***2***");
s1 = "";
s2 = null;
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//false
s1 = s2;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
System.out.println("***3***");
s1 = "";
s2 = "";
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***4***");
s1 = new String("");
s2 = new String("");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***5***");
s1 = "null";
s2 = "null";
System.out.println(s1==s2);//ture
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***6***");
s1 = new String("null");
s2 = new String("null");
System.out.println(s1==s2);//flase
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***7***");
s1 = "abc";
s2 = "abc";
System.out.println(s1==s2);//ture
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***8***");
s1 = new String("abc");
s2 = new String("abc");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***9***");
總結: 多數情況下這兩者的區別就是究竟是對對象的引用進行比較還是對對象的值進行比較(其他特殊情況此處不予考慮)。==操作符是比較的對象的引用而不是對象的值。
但在最初的Object對象中的equals方法與==操作符完成功能是相同的。
源碼:
java.lang.Object.equals()方法:
-------------------------------------------------------------
public boolean equalss(Object obj) {
return (this = = obj);
}
-------------------------------------------------------------
jdk文檔中給出如下解釋:
-------------------------------------------------------------
The equalss method implements an equivalence relation:
· It is reflexive: for any reference value x, x.equalss(x) should return true.
· It is symmetric: for any reference values x and y, x.equalss(y) should return true if and only if y.equalss(x) returns true.
· It is transitive: for any reference values x, y, and z, if x.equalss(y) returns true and y.equalss(z) returns true, then x.equalss(z) should return true.
· It is consistent: for any reference values x and y, multiple invocations of x.equalss(y) consistently return true or consistently return false, provided no information used in equalss comparisons on the object is modified.
· For any non-null reference value x, x.equalss(null) should return false.
The equalss method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any reference values x and y, this method returns true if and only if x and y refer to the same object (x==y has the value true).
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equals objects must have equals hash codes.
-------------------------------------------------------------
對于String類的equals方法是對什么內容進行比較的呢?下面我們來看它的代碼和注釋:
源代碼:
-------------------------------------------------------------
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;
}
-------------------------------------------------------------
此方法的注釋為:
-------------------------------------------------------------
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
-------------------------------------------------------------
由上面的代碼和注釋可以得到String類的equal方法是對對象的值進行比較。
根據以上的討論可以得出結論:equal方法和==操作符是否存在區別要個別對待,要根據equal的每個實現情況來具體判斷。
tomcat5.5.9 jdbc 連接池配置時常會出現兩個錯誤:
1.***not bound
2.Cannot create JDBC driver of class '' for connect URL 'null'
可以通過以下的方法達到正確的配置:
1.現在%tomcat home%/conf/catalina/localhost 下面添加一段獨立的context xml段,命名為jasper.xml,例如
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/jasper" docBase="jasper" debug="1" reloadable="true" crossContext="true">
</Context>
2.通過admin的界面(或手動在server.xml界面里進行配置)數據源,以sql2k為例,配置后的server.xml應該為
<?xml version="1.0" encoding="UTF-8"?>
<Server>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"/>
<GlobalNamingResources>
<Environment
name="simpleValue"
type="java.lang.Integer"
value="30"/>
<Resource
auth="Container"
description="User database that can be updated and saved"
name="UserDatabase"
type="org.apache.catalina.UserDatabase"
pathname="conf/tomcat-users.xml"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"/>
<Resource
name="jdbc/Northwind"
type="javax.sql.DataSource"
password="*****"
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
maxIdle="2"
maxWait="5000"
username="sa"
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=Northwind"
maxActive="20"/>
</GlobalNamingResources>
<Service
name="Catalina">
<Connector
port="80"
redirectPort="8443"
minSpareThreads="25"
connectionTimeout="20000"
maxSpareThreads="75"
maxThreads="150"
maxHttpHeaderSize="8192">
</Connector>
<Connector
port="8009"
redirectPort="8443"
protocol="AJP/1.3">
</Connector>
<Engine
defaultHost="localhost"
name="Catalina">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"/>
<Host
appBase="webapps"
name="localhost">
</Host>
</Engine>
</Service>
</Server>
3.在conf下面的context.xml文件中,</Context>之前加入
<ResourceLink name="jdbc/Northwind" global="jdbc/Northwind" type="javax.sql.DataSourcer"/>
4.在你的web文件夾下面的WEB-INF中找到web.xml,在最后</web-app>之前加入
<resource-ref>
<description>Northwind Connection</description>
<res-ref-name>jdbc/Northwind</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
5.保存,重啟tomcat,這樣,通過測試頁面,就可以發現已經可以通過數據庫連接池連上sql2k
test1.jsp
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<%@page import="javax.naming.*"%>
<%@page import="javax.sql.*"%>
<%
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/Northwind");
Connection conn = ds.getConnection();
int counts=0;
String sql="select count(*) from orders";
PreparedStatement pst=conn.prepareStatement(sql);
ResultSet rst=pst.executeQuery();
while(rst.next()){
counts=rst.getInt(1);
}
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>JNDI 測試</title>
</head>
<body>
<%=sql%><br>
pnrreg talbe's count is:<%=counts%>
</body>
</html>
摘要: JS的正則表達式
//校驗是否全由數字組成
function isDigit(s)
{
var patrn=/^[0-9]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗登錄名:只能輸入5-20個以字母開頭、可帶數字、“_”... 閱讀全文
原著:Steve Mansour
sman@scruznet.com
Revised: June 5, 1999
(copied by jm /at/ jmason.org from http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! )
翻譯:Neo Lee
neo.lee@gmail.com
2004年10月16日
英文版原文
譯者按:原文因為年代久遠,文中很多鏈接早已過期(主要是關于vi、sed等工具的介紹和手冊),本譯文中已將此類鏈接刪除,如需檢查這些鏈接可以查看上面鏈接的原文。除此之外基本照原文直譯,括號中有“譯者按”的部分是譯者補充的說明。如有內容方面的問題請直接和Steve Mansor聯系,當然,如果你只寫中文,也可以和我聯系。
目 錄
什么是正則表達式
范例
簡單
中級(神奇的咒語)
困難(不可思議的象形文字)
不同工具中的正則表達式
什么是正則表達式
一個正則表達式,就是用某種模式去匹配一類字符串的一個公式。很多人因為它們看上去比較古怪而且復雜所以不敢去使用——很不幸,這篇文章也不能夠改變這一點,不過,經過一點點練習之后我就開始覺得這些復雜的表達式其實寫起來還是相當簡單的,而且,一旦你弄懂它們,你就能把數小時辛苦而且易錯的文本處理工作壓縮在幾分鐘(甚至幾秒鐘)內完成。正則表達式被各種文本編輯軟件、類庫(例如Rogue Wave的tools.h++)、腳本工具(像awk/grep/sed)廣泛的支持,而且像Microsoft的Visual C++這種交互式IDE也開始支持它了。
我們將在如下的章節中利用一些例子來解釋正則表達式的用法,絕大部分的例子是基于vi中的文本替換命令和grep文件搜索命令來書寫的,不過它們都是比較典型的例子,其中的概念可以在sed、awk、perl和其他支持正則表達式的編程語言中使用。你可以看看不同工具中的正則表達式這一節,其中有一些在別的工具中使用正則表達式的例子。還有一個關于vi中文本替換命令(s)的簡單說明附在文后供參考。
正則表達式基礎
正則表達式由一些普通字符和一些 元字符(metacharacters)組成。普通字符包括大小寫的字母和數字,而元字符則具有特殊的含義,我們下面會給予解釋。
在最簡單的情況下,一個正則表達式看上去就是一個普通的查找串。例如,正則表達式"testing"中沒有包含任何元字符,,它可以匹配"testing"和"123testing"等字符串,但是不能匹配"Testing"。
要想真正的用好正則表達式,正確的理解元字符是最重要的事情。下表列出了所有的元字符和對它們的一個簡短的描述。
元字符 |
|
描述 |
|
|
|
. |
|
匹配任何單個字符。例如正則表達式r.t匹配這些字符串:rat、rut、r t,但是不匹配root。 |
$ |
|
匹配行結束符。例如正則表達式weasel$ 能夠匹配字符串"He's a weasel"的末尾,但是不能匹配字符串"They are a bunch of weasels."。 |
^ |
|
匹配一行的開始。例如正則表達式^When in能夠匹配字符串"When in the course of human events"的開始,但是不能匹配"What and When in the"。 |
* |
|
匹配0或多個正好在它之前的那個字符。例如正則表達式.*意味著能夠匹配任意數量的任何字符。 |
\ |
|
這是引用府,用來將這里列出的這些元字符當作普通的字符來進行匹配。例如正則表達式\$被用來匹配美元符號,而不是行尾,類似的,正則表達式\.用來匹配點字符,而不是任何字符的通配符。 |
[ ]
[c1-c2]
[^c1-c2] |
|
匹配括號中的任何一個字符。例如正則表達式r[aou]t匹配rat、rot和rut,但是不匹配ret。可以在括號中使用連字符-來指定字符的區間,例如正則表達式[0-9]可以匹配任何數字字符;還可以制定多個區間,例如正則表達式[A-Za-z]可以匹配任何大小寫字母。另一個重要的用法是“排除”,要想匹配除了指定區間之外的字符——也就是所謂的補集——在左邊的括號和第一個字符之間使用^字符,例如正則表達式[^269A-Z] 將匹配除了2、6、9和所有大寫字母之外的任何字符。 |
\< \> |
|
匹配詞(word)的開始(\<)和結束(\>)。例如正則表達式\<the能夠匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:這個元字符不是所有的軟件都支持的。 |
\( \) |
|
將 \( 和 \) 之間的表達式定義為“組”(group),并且將匹配這個表達式的字符保存到一個臨時區域(一個正則表達式中最多可以保存9個),它們可以用 \1 到\9 的符號來引用。 |
| |
|
將兩個匹配條件進行邏輯“或”(Or)運算。例如正則表達式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:這個元字符不是所有的軟件都支持的。 |
+ |
|
匹配1或多個正好在它之前的那個字符。例如正則表達式9+匹配9、99、999等。注意:這個元字符不是所有的軟件都支持的。 |
? |
|
匹配0或1個正好在它之前的那個字符。注意:這個元字符不是所有的軟件都支持的。 |
\{i\}
\{i,j\} |
|
匹配指定數目的字符,這些字符是在它之前的表達式定義的。例如正則表達式A[0-9]\{3\} 能夠匹配字符"A"后面跟著正好3個數字字符的串,例如A123、A348等,但是不匹配A1234。而正則表達式[0-9]\{4,6\} 匹配連續的任意4個、5個或者6個數字字符。注意:這個元字符不是所有的軟件都支持的。 |
最簡單的元字符是點,它能夠匹配任何單個字符(注意不包括新行符)。假定有個文件test.txt包含以下幾行內容:
he is a rat
he is in a rut
the food is Rotten
I like root beer
我們可以使用grep命令來測試我們的正則表達式,grep命令使用正則表達式去嘗試匹配指定文件的每一行,并將至少有一處匹配表達式的所有行顯示出來。命令
在test.txt文件中的每一行中搜索正則表達式 r.t,并打印輸出匹配的行。正則表達式 r.t匹配一個 r接著任何一個字符再接著一個 t。所以它將匹配文件中的 rat和 rut,而不能匹配 Rotten中的 Rot,因為正則表達式是大小寫敏感的。要想同時匹配大寫和小寫字母,應該使用字符區間元字符(方括號)。正則表達式 [Rr]能夠同時匹配 R和 r。所以,要想匹配一個大寫或者小寫的 r接著任何一個字符再接著一個 t就要使用這個表達式: [Rr].t。
要想匹配行首的字符要使用抑揚字符(^)——又是也被叫做插入符。例如,想找到text.txt中行首"he"打頭的行,你可能會先用簡單表達式he,但是這會匹配第三行的the,所以要使用正則表達式^he,它只匹配在行首出現的h。
有時候指定“除了×××都匹配”會比較容易達到目的,當抑揚字符(^)出現在方括號中是,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情性(也就是the和she),可以使用:[^st]he。
可以使用方括號來指定多個字符區間。例如正則表達式[A-Za-z]匹配任何字母,包括大寫和小寫的;正則表達式[A-Za-z][A-Za-z]* 匹配一個字母后面接著0或者多個字母(大寫或者小寫)。當然我們也可以用元字符+做到同樣的事情,也就是:[A-Za-z]+ ,和[A-Za-z][A-Za-z]*完全等價。但是要注意元字符+ 并不是所有支持正則表達式的程序都支持的。關于這一點可以參考后面的正則表達式語法支持情況。
要指定特定數量的匹配,要使用大括號(注意必須使用反斜杠來轉義)。想匹配所有100和1000的實例而排除10和10000,可以使用:10\{2,3\},這個正則表達式匹配數字1后面跟著2或者3個0的模式。在這個元字符的使用中一個有用的變化是忽略第二個數字,例如正則表達式0\{3,\} 將匹配至少3個連續的0。
簡單的例子
這里有一些有代表性的、比較簡單的例子。
vi 命令 |
作用 |
|
|
:%s/ */ /g |
把一個或者多個空格替換為一個空格。 |
:%s/ *$// |
去掉行尾的所有空格。 |
:%s/^/ / |
在每一行頭上加入一個空格。 |
:%s/^[0-9][0-9]* // |
去掉行首的所有數字字符。 |
:%s/b[aeio]g/bug/g |
將所有的bag、beg、big和bog改為bug。 |
:%s/t\([aou]\)g/h\1t/g |
將所有tag、tog和tug分別改為hat、hot和hug(注意用group的用法和使用\1引用前面被匹配的字符)。 |
|
|
中級的例子(神奇的咒語)
例1
將所有方法foo(a,b,c)的實例改為foo(b,a,c)。這里a、b和c可以是任何提供給方法foo()的參數。也就是說我們要實現這樣的轉換:
之前 |
|
之后 |
foo(10,7,2) |
|
foo(7,10,2) |
foo(x+13,y-2,10) |
|
foo(y-2,x+13,10) |
foo( bar(8), x+y+z, 5) |
|
foo( x+y+z, bar(8), 5) |
下面這條替換命令能夠實現這一魔法:
:%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g
現在讓我們把它打散來加以分析。寫出這個表達式的基本思路是找出foo()和它的括號中的三個參數的位置。第一個參數是用這個表達式來識別的::\([^,]*\),我們可以從里向外來分析它:
[^,] |
|
除了逗號之外的任何字符 |
[^,]* |
|
0或者多個非逗號字符 |
\([^,]*\) |
|
將這些非逗號字符標記為\1,這樣可以在之后的替換模式表達式中引用它 |
\([^,]*\), |
|
我們必須找到0或者多個非逗號字符后面跟著一個逗號,并且非逗號字符那部分要標記出來以備后用。 |
現在正是指出一個使用正則表達式常見錯誤的最佳時機。為什么我們要使用[^,]*這樣的一個表達式,而不是更加簡單直接的寫法,例如:.*,來匹配第一個參數呢?設想我們使用模式.*來匹配字符串"10,7,2",它應該匹配"10,"還是"10,7,"?為了解決這個兩義性(ambiguity),正則表達式規定一律按照最長的串來,在上面的例子中就是"10,7,",顯然這樣就找出了兩個參數而不是我們期望的一個。所以,我們要使用[^,]*來強制取出第一個逗號之前的部分。
這個表達式我們已經分析到了:foo(\([^,]*\),這一段可以簡單的翻譯為“當你找到foo(就把其后直到第一個逗號之前的部分標記為\1”。然后我們使用同樣的辦法標記第二個參數為\2。對第三個參數的標記方法也是一樣,只是我們要搜索所有的字符直到右括號。我們并沒有必要去搜索第三個參數,因為我們不需要調整它的位置,但是這樣的模式能夠保證我們只去替換那些有三個參數的foo()方法調用,在foo()是一個重載(overoading)方法時這種明確的模式往往是比較保險的。然后,在替換部分,我們找到foo()的對應實例,然后利用標記好的部分進行替換,是的第一和第二個參數交換位置。
例2
假設有一個CSV(comma separated value)文件,里面有一些我們需要的信息,但是格式卻有問題,目前數據的列順序是:姓名,公司名,州名縮寫,郵政編碼,現在我們希望講這些數據重新組織,以便在我們的某個軟件中使用,需要的格式為:姓名,州名縮寫-郵政編碼,公司名。也就是說,我們要調整列順序,還要合并兩個列來構成一個新列。另外,我們的軟件不能接受逗號前后面有任何空格(包括空格和制表符)所以我們還必須要去掉逗號前后的所有空格。
這里有幾行我們現在的數據:
Bill Jones, HI-TEK Corporation , CA, 95011
Sharon Lee Smith, Design Works Incorporated, CA, 95012
B. Amos , Hill Street Cafe, CA, 95013
Alexander Weatherworth, The Crafts Store, CA, 95014
...
我們希望把它變成這個樣子:
Bill Jones,CA 95011,HI-TEK Corporation
Sharon Lee Smith,CA 95012,Design Works Incorporated
B. Amos,CA 95013,Hill Street Cafe
Alexander Weatherworth,CA 95014,The Crafts Store
...
我們將用兩個正則表達式來解決這個問題。第一個移動列和合并列,第二個用來去掉空格。
下面就是第一個替換命令:
:%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/
這里的方法跟例1基本一樣,第一個列(姓名)用這個表達式來匹配: \([^,]*\),即第一個逗號之前的所有字符,而姓名內容被用 \1標記下來。公司名和州名縮寫字段用同樣的方法標記為 \2和 \3,而最后一個字段用 \(.*\)來匹配("匹配所有字符直到行末")。替換部分則引用上面標記的那些內容來進行構造。
下面這個替換命令則用來去除空格:
我們還是分解來看: [ \t]匹配空格/制表符, [ \t]* 匹配0或多個空格/制表符, [ \t]*,匹配0或多個空格/制表符后面再加一個逗號,最后, [ \t]*,[ \t]*匹配0或多個空格/制表符接著一個逗號再接著0或多個空格/制表符。在替換部分,我們簡單的我們找到的所有東西替換成一個逗號。這里我們使用了結尾的可選的 g參數,這表示在每行中對所有匹配的串執行替換(而不是缺省的只替換第一個匹配串)。
例3
假設有一個多字符的片斷重復出現,例如:
Billy tried really hard
Sally tried really really hard
Timmy tried really really really hard
Johnny tried really really really really hard 而你想把"really"、"really really",以及任意數量連續出現的"really"字符串換成一個簡單的"very"(simple is good!),那么以下命令:
:%s/\(really \)\(really \)*/very / 就會把上述的文本變成:
Billy tried very hard
Sally tried very hard
Timmy tried very hard
Johnny tried very hard 表達式 \(really \)*匹配0或多個連續的"really "(注意結尾有個空格),而 \(really \)\(really \)* 匹配1個或多個連續的"really "實例。
困難的例子(不可思議的象形文字)
Coming soon.
不同工具中的正則表達式
OK,你已經準備使用RE(regular expressions,正則表達式),但是你并準備使用vi。所以,在這里我們給出一些在其他工具中使用RE的例子。另外,我還會總結一下你在不同程序之間使用RE可能發現的區別。
當然,你也可以在Visual C++編輯器中使用RE。選擇Edit->Replace,然后選擇"Regular expression"選擇框,Find What輸入框對應上面介紹的vi命令:%s/pat1/pat2/g中的pat1部分,而Replace輸入框對應pat2部分。但是,為了得到vi的執行范圍和g選項,你要使用Replace All或者適當的手工Find Next and Replace(譯者按:知道為啥有人罵微軟弱智了吧,雖然VC中可以選中一個范圍的文本,然后在其中執行替換,但是總之不夠vi那么靈活和典雅)。
sed
Sed是Stream EDitor的縮寫,是Unix下常用的基于文件和管道的編輯工具,可以在手冊中得到關于sed的詳細信息。
這里是一些有趣的sed腳本,假定我們正在處理一個叫做price.txt的文件。注意這些編輯并不會改變源文件,sed只是處理源文件的每一行并把結果顯示在標準輸出中(當然很容易使用重定向來定制):
sed腳本 |
|
描述 |
|
|
|
sed 's/^$/d' price.txt |
|
刪除所有空行 |
sed 's/^[ \t]*$/d' price.txt |
|
刪除所有只包含空格或者制表符的行 |
sed 's/"http://g' price.txt |
|
刪除所有引號 |
awk
awk是一種編程語言,可以用來對文本數據進行復雜的分析和處理。可以在手冊中得到關于awk的詳細信息。這個古怪的名字是它作者們的姓的縮寫(Aho,Weinberger和Kernighan)。
在Aho,Weinberger和Kernighan的書The AWK Programming Language中有很多很好的awk的例子,請不要讓下面這些微不足道的腳本例子限制你對awk強大能力的理解。我們同樣假定我們針對price.txt文件進行處理,跟sed一樣,awk也只是把結果顯示在終端上。
awk腳本 |
|
描述 |
|
|
|
awk '$0 !~ /^$/' price.txt |
|
刪除所有空行 |
awk 'NF > 0' price.txt |
|
awk中一個更好的刪除所有行的辦法 |
awk '$2 ~ /^[JT]/ {print $3}' price.txt |
|
打印所有第二個字段是'J'或者'T'打頭的行中的第三個字段 |
awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt |
|
針對所有第二個字段不包含'Misc'或者'misc'的行,打印第3和第4列的和(假定為數字) |
awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt |
|
打印所有第三個字段不是數字的行,這里數字是指d.d或者d這樣的形式,其中d是0到9的任何數字 |
awk '$2 ~ /John|Fred/ {print $0}' price.txt |
|
如果第二個字段包含'John'或者'Fred'則打印整行 |
grep
grep是一個用來在一個或者多個文件或者輸入流中使用RE進行查找的程序。它的name編程語言可以用來針對文件和管道進行處理。可以在手冊中得到關于grep的完整信息。這個同樣古怪的名字來源于vi的一個命令, g/re/p,意思是 global regular expression print。
下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個逗號,然后是名,然后是一個制表符,然后是電話號碼:
Francis, John 5-3871
Wong, Fred 4-4123
Jones, Thomas 1-4122
Salazar, Richard 5-2522
grep命令 |
|
描述 |
|
|
|
grep '\t5-...1' phone.txt |
|
把所有電話號碼以5開頭以1結束的行打印出來,注意制表符是用\t表示的 |
grep '^S[^ ]* R' phone.txt |
|
打印所有姓以S打頭和名以R打頭的行 |
grep '^[JW]' phone.txt |
|
打印所有姓開頭是J或者W的行 |
grep ', ....\t' phone.txt |
|
打印所有姓是4個字符的行,注意制表符是用\t表示的 |
grep -v '^[JW]' phone.txt |
|
打印所有不以J或者W開頭的行 |
grep '^[M-Z]' phone.txt |
|
打印所有姓的開頭是M到Z之間任一字符的行 |
grep '^[M-Z].*[12]' phone.txt |
|
打印所有姓的開頭是M到Z之間任一字符,并且點號號碼結尾是1或者2的行 |
egrep
egrep是grep的一個擴展版本,它在它的正則表達式中支持更多的元字符。下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個逗號,然后是名,然后是一個制表符,然后是電話號碼:
Francis, John 5-3871
Wong, Fred 4-4123
Jones, Thomas 1-4122
Salazar, Richard 5-2522
egrep command |
|
Description |
|
|
|
egrep '(John|Fred)' phone.txt |
|
打印所有包含名字John或者Fred的行 |
egrep 'John|22$|^W' phone.txt |
|
打印所有包含John 或者以22結束或者以W的行 |
egrep 'net(work)?s' report.txt |
|
從report.txt中找到所有包含networks或者nets的行 |
正則表達式語法支持情況
命令或環境 |
. |
[ ] |
^ |
$ |
\( \) |
\{ \} |
? |
+ |
| |
( ) |
vi |
X |
X |
X |
X |
X |
|
|
|
|
|
Visual C++ |
X |
X |
X |
X |
X |
|
|
|
|
|
awk |
X |
X |
X |
X |
|
|
X |
X |
X |
X |
sed |
X |
X |
X |
X |
X |
X |
|
|
|
|
Tcl |
X |
X |
X |
X |
X |
|
X |
X |
X |
X |
ex |
X |
X |
X |
X |
X |
X |
|
|
|
|
grep |
X |
X |
X |
X |
X |
X |
|
|
|
|
egrep |
X |
X |
X |
X |
X |
|
X |
X |
X |
X |
fgrep |
X |
X |
X |
X |
X |
|
|
|
|
|
perl |
X |
X |
X |
X |
X |
|
X |
X |
X |
X |
vi替換命令簡介
Vi的替換命令:
其中
網上有很多vi的在線手冊,你可以訪問他們以獲得更加完整的信息。
已知: 字段A='F:\photo\Winter Leaves.jpg'
要求:分段截取每段字符[字段A不能為TEXT類型,否則報錯]
解決方法:
+++++++++++++++++++++++++++++++++++++++++++++++++++
---截取字符串A的第一個\左邊的字符串
select left(A,charindex('/',A)-1)
輸出結果:F:
++++++++++++++++++++++++++++++++++++++++++++++++++++
---截取\中間的字符串
select left(stuff(A,1,charindex('/',A),''),charindex('/',stuff(A,1,charindex('/',A),''))-1)
輸出結果:photo
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
---截取最后一個\后面的字符串
select reverse(left(reverse(A),charindex('/',reverse(A))-1))
輸出結果:Winter Leaves.jpg
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
---截取字符串A的首字幕
select STUFF(A,1, 1, '')
輸出結果::\photo\Winter Leaves.jpg
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
把你的光標放到相應文字上查看效果
|
要注意光標的實際效果依賴于用戶的系統設置,與你在這里看到的效果并不一定一致。
|
cursor: crosshair;
|
|
十字準心
|
The cursor render as a crosshair
游標表現為十字準線
|
cursor: pointer;
cursor: hand;
寫兩個是為了照顧IE5,它只認hand。
|
|
手
|
The cursor render as a pointer (a hand) that indicates a link
游標以暗示(手指)的形式來表明有一個連接
|
cursor: wait;
|
|
等待/沙漏
|
The cursor indicates that the program is busy (often a watch or an hourglass)
游標暗示當前程序正忙(一般為一塊表或是一個沙漏)
|
cursor: help;
|
|
幫助
|
The cursor indicates that help is available (often a question mark or a balloon)
游標暗示當前位置可得到幫助(一般為問號或是氣球)
|
cursor: no-drop;
|
|
無法釋放
|
cursor: no-drop;
|
cursor: text;
|
|
文字/編輯
|
The cursor indicates text
游標暗示當前所處位置為文字內容
|
cursor: move;
|
|
可移動對象
|
The cursor indicates something that should be moved
游標暗示一些東西應該被移動
|
cursor: n-resize;
|
|
向上改變大小(North)
|
The cursor indicates that an edge of a box is to be moved up (north)
邊緣可向上移動(北)
|
cursor: s-resize;
|
|
向下改變大小(South)
|
The cursor indicates that an edge of a box is to be moved down (south)
邊緣可向下方移動(南)
|
cursor: e-resize;
|
|
向右改變大小(East)
|
The cursor indicates that an edge of a box is to be moved right (east)
box邊緣可向右(東)邊移動
|
cursor: w-resize;
|
|
向左改變大小(West)
|
The cursor indicates that an edge of a box is to be moved left (west)
邊緣可向左移動(西)
|
cursor: ne-resize;
|
|
向上右改變大小(North East)
|
The cursor indicates that an edge of a box is to be moved up and right (north/east)
游標暗示box的邊緣可向右上方移動(東北方向)
|
cursor: nw-resize;
|
|
向上左改變大小(North West)
|
The cursor indicates that an edge of a box is to be moved up and left (north/west)
邊緣可向左上方移動(西北)
|
cursor: se-resize;
|
|
向下右改變大小(South East)
|
The cursor indicates that an edge of a box is to be moved down and right (south/east)
邊緣可向右下方移動(東南)
|
cursor: sw-resize;
|
|
向下左改變大小(South West)
|
The cursor indicates that an edge of a box is to be moved down and left (south/west)
邊緣可向左下方移動(西南)
|
cursor: auto;
|
|
自動
|
The browser sets a cursor
瀏覽器設置一個游標
|
cursor:not-allowed;
|
|
禁止
|
cursor:not-allowed;
|
cursor: progress;
|
|
處理中
|
cursor: progress;
|
cursor: default;
|
|
系統默認
|
The default cursor (often an arrow)
默認的游標狀態(通常為一個箭頭)
|
cursor: url(' # ');
# = 光標文件地址 (注意文件格式必須為:.cur 或 .ani)。
|
|
用戶自定義(可用動畫)
|
The url of a custom cursor to be used.
自定義游標的url位置
Note: Always define a generic cursor at the end of the list in case none of the url-defined cursors can be used
注意:在定義完自定義的游標之后在末尾加上一般性的游標,以防那些url所定義的游標不能使用
|
Logo生成網站:
天空秘書網,J/m!h._HK&Rq 強烈推薦:http://www.logomaker.cn
http://phorum.com.tw/Generator.aspx 天空秘書網,VK2V#J&t#W`*A http://www.logoyes.com/lc_leftframe.htm 天空秘書網&jD-L|;X+O8c http://cooltext.com/Default.aspx
Banner圖片制作網站:
http://www.bannerbreak.com/index.php
在線圖片生成網站:
http://www.streetsigngenerator.com/ %u` U l5e&Bt;Fd0http://www.letterjames.de/
圖片分割器: http://www.html-kit.com/e/is.cgi
立體圖片生成器: http://www.chami.com/html-kit/services/imge/
圖片生成郵票: http://photo.stamps.com/PhotoStamps/?source=si00001331
個性拼圖: http://www.jigcool.com/jigonline/jigonline1_sc.php
印章制作: http://caishu.sina.com.cn/
GIF圖片的文字LOGO在線生成:http://www.3dtextmaker.com/cgi-bin/3dtext.pl
在線制作logo,bannar的網站:http://www.crazystudy.com
SAINT.Assess the Security of Computer Networks :http://www.saintcorporation.com/saint/
Abacus.Intrusion Prevention System :http://www.psionic.com/abacus/
Firewall Generator(在線生成簡單的防火墻腳本)
http://www.citadec.com/FirewallGenerator.html
在線字體圖片生成:http://www.youmade.com/font/
在線生成條碼打印
http://www.027hc.com/y1.asp [tG+|$M{~/@"dV0http://www.nlscan.com/soucecentre/demo.asp #U|TA I%F Ts0http://www.gzbonny.com/asp/barcode.asp
在線圖形特效生成:http://www.chami.com/
聊天工具在線狀態生成器:http://www.onlinestatus.org/forum/usage.php
粉絲身份證:http://id.igogo8.com/
制作印章:http://www.makepic.com/print.php
郵址圖片生成:http://www.makepic.com/email.php
條形碼生成:http://www.makepic.com/barcode.php
Kiss學堂 頒發結業證:http://www.makepic.com/kiss/cert.php
生成頭像:http://www.eoool.com/ImageDIY/DIYChooseImg.aspx?ImgSize=96x96x1
郵件:http://www.eoool.com/Sevice.aspx?TypeID=1
聊天圖標:http://www.eoool.com/Sevice.aspx?TypeID=2
博客圖標:http://www.eoool.com/Sevice.aspx?TypeID=3
網絡書簽:http://www.eoool.com/Sevice.aspx?TypeID=5
朋友圈:http://www.eoool.com/Sevice.aspx?TypeID=4
按扭:http://www.eoool.com/Sevice.aspx?TypeID=11
生成拼湊圖:http://blog.outer-court.com/letters/
一個日本武士刀劈出你需要的字:
http://tools.fodey.com/generators/animated/ninjatext.asp
生成幾種卡通人物對話動態圖片:
http://tools.fodey.com/generators/animated/talking_squirrel.asp天空秘書網P R_9]H,|,x
^0g3pI#}5l;z.v`F0香煙盒生成,可以做警告圖片:http://tools.fodey.com/generators/cigarette_packet/generator.cig
支持多種域名的Email圖標的生成: http://www.nhacks.com/email/
兩個地址支持兩種風格任意文本的Email圖標的生成:
http://sagittarius.dip.jp/~toshi/cgi-bin/designmail/designmail.html天空秘書網Q T2z6^9~ \8kZ g'IW http://sagittarius.dip.jp/~toshi/cgi-bin/catmark/catmark.html
在線favicon生成器: http://www.html-kit.com/e/favicon.cgi
支持各種類型圖片的生成,可以選擇設置的條件非常靈活:
http://www.abi-station.com/tchinese/
支持大量中文字體簽名圖標生成: http://www.youmade.com/font/
Flickr雜志封面生成器: http://flagrantdisregard.com/flickr/magazine.php
動態生成有趣圖片:
愛因斯坦:http://www.hetemeel.com/einsteinform.php
山姆大叔:http://www.hetemeel.com/unclesamform.php
辭典:http://www.hetemeel.com/dictionaryform.php
魔法師:http://www.imagegenerator.net/create/dumbledore/
Flickr Logo風格圖片生成器::http://flickr.nosv.org/
按鈕生成網站:
http://kalsey.com/tools/buttonmaker/ %u"l*FdqLp X8K9A6Z]0http://www.lucazappa.com/brilliantMaker/buttonImage.php天空秘書網A,W!s)[c{ http://www.feedforall.com/public/rss-graphic-tool.htm天空秘書網L|e"j*BP8kS0A http://www.kalsey.com/tools/buttonmaker/ y$A Si1Y&N/Z0http://www.yugatech.com/make.php天空秘書網R SS2_ E^9[.O http://www.hkwebs.net/catalog/tools/buttonmaker/index.php
Email圖標生成網站::
http://email.playtime.uni.cc/ :y]~5d'[d3L Y+k$j0http://services.nexodyne.com/email/ 6nPlesL0http://gizmo967.mgs3.org/Gmail/ R-GD kl3[z0http://www.hkwebs.net/catalog/tools/gmail/ 天空秘書網;N5ha5a*V`P3` http://sagittarius.dip.jp/~toshi/cgi-bin/designmail/designmail.html ~z'Z'GK%h4cq0http://www.eoool.com/
匹配中文字符的正則表達式: [\u4e00-\u9fa5]
匹配雙字節字符(包括漢字在內):[^\x00-\xff]
應用:計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1)
String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}
匹配空行的正則表達式:\n[\s| ]*\r
匹配HTML標記的正則表達式:/<(.*)>.*<\/\1>|<(.*) \/>/
匹配首尾空格的正則表達式:(^\s*)|(\s*$)
應用:javascript中沒有像vbscript那樣的trim函數,我們就可以利用這個表達式來實現,如下:
String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }
利用正則表達式分解和轉換IP地址:
下面是利用正則表達式匹配IP地址,并將IP地址轉換成對應數值的Javascript程序:
function IP2V(ip) { re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正則表達式 if(re.test(ip)) { return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1 } else { throw new Error("Not a valid IP address!") } }
不過上面的程序如果不用正則表達式,而直接用split函數來分解可能更簡單,程序如下:
var ip="10.100.20.168" ip=ip.split(".") alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))
匹配Email地址的正則表達式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配網址URL的正則表達式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
利用正則表達式去除字串中重復的字符的算法程序:
var s="abacabefgeeii" var s1=s.replace(/(.).*\1/g,"$1") var re=new RegExp("["+s1+"]","g") var s2=s.replace(re,"") alert(s1+s2) //結果為:abcefgi
我原來在CSDN上發貼尋求一個表達式來實現去除重復字符的方法,最終沒有找到,這是我能想到的最簡單的實現方法。思路是使用后向引用取出包括重復的字符,再以重復的字符建立第二個表達式,取到不重復的字符,兩者串連。這個方法對于字符順序有要求的字符串可能不適用。
得用正則表達式從URL地址中提取文件名的javascript程序,如下結果為page1
s="http://www.gzcynet/page1.htm" s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2") alert(s)
利用正則表達式限制網頁表單里的文本框輸入內容:
用正則表達式限制只能輸入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"
用正則表達式限制只能輸入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"
用正則表達式限制只能輸入數字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
用正則表達式限制只能輸入數字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
下面四個都是檢查email的...
^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$
^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$
^.+@[^\.].*\.[a-z]{2,}$
^[\w\.=-]+@[\w\.-]+\.[\w]{2,3}$
模型驅動架構(MDA)是一種獨立于特定平臺和軟件供應商的軟件體系結構設計和開發方法,它適用于設計、部署、集成等軟件開發的整個生命周期。MDA 遵循的是諸如統一建模語言(UML)、可擴展標記語言(XML)和公共對象請求代理體系結構(CORBA)等一系列業界開放標準。
MDA 建模是基于功能,而非基于特定語言、平臺或實現技術,它可以簡化系統集成、縮短開發周期和節省企業資源。
模型通常以圖和文字的形式來描述一個系統及其環境。模型驅動的方法就是利用模型來引導系統的設計、開發和維護。而模型驅動架構即是用系統的模型來生成系統的體系結構。
MDA 有三個視圖。第一個視圖叫“計算無關視圖(CIV)”,其作用就是將系統基本處理邏輯同平臺相關的技術規范分離開來。CIV視圖關注于系統的環境和需求,而系統的具體結構和實現是隱藏的。
第二個視圖是“平臺無關視圖(PIV)”。該視圖關注于系統的操作而隱藏了平臺相關的細節,該視圖可能用一種通用的、平臺無關的建模語言如UML來描述。
第三個視圖叫“平臺相關視圖(PSV)”。該視圖關注特定平臺的實現細節。
以上三個視圖都有其各自相應的模型:
- 計算無關模型(CIM)通常由業務分析人員創建,展示了系統的業務模型。
- 平臺無關模型(PIM)是系統功能的模型,通常由系統架構師創建。
- 平臺相關模型(PSM)對一個或多個平臺的PIM模型的具體實現建模。
MDA 的真正價值在于 CIM 模型可以通過簡單的映射轉換成 PIM 模型。同樣的,PIM 模型也可以映射成 PSM 模型,而 PSM 模型則可以最終轉換成具體的實現代碼。
如下圖所示,右上角的 CIM 模型是整個模型轉換過程的起點。CIM 模型轉換成 PIM 模型后,系統架構師和設計師即可以創建系統其余部分的模型。設計完成之后,PIM 模型就轉換成了一個或多個 PSM 模型。
|

模型驅動架構 (MDA)
|
MDA 提供了一種優雅而可靠的開發框架,這種框架使得系統架構師在沒有考慮到有關系統實現的任何細節之前就可以事先定義好系統的模型。
MDA 的優勢主要包括如下幾點:
- 可移植性 -當你創建好一個 PIM 模型之后,創建一個新的基于該 PIM 模型的 PSM 模型是相當容易的。當然,你需要到目標平臺的映射規則和一些連接代碼。
- 跨平臺的互操作性 - 除了可以將一個系統模型轉化為不同的實現,你也可以使用一種特殊的映射規則將一個 PIM 模型轉化為一個異構的 PSM 模型,在該異構模型中,最終的系統是由來自多個平臺的組件構建而成的。
- 開發效率 - MDA 是一種極其高效的設計和開發方法。使用 MDA 方法可以以更少的人力來完成原先相同的工作量,或者以原先相同的人力來完成更多的工作,所有這些都無需對開發團隊施加額外的壓力。
- 軟件質量 - 使用一種單一的模型來生成和導出系統的大部分代碼可以極大地降低人為錯誤的發生。
MDA 還有其它更多的優勢,如對新技術的快速包容、平臺無關性、領域相關性、降低開發成本和縮短開發周期等等。
|
文件的建立/檢查與刪除 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>文件的建立、檢查與刪除</title> </head> <body> <% String path=request.getRealPath(""); //out.println(path); File f=new File(path,"File.txt"); //out.println(f); //out.println(f.exists());
if(f.exists()){//檢查File.txt是否存在 f.delete();//刪除File.txt文件 out.println(path + "\\File.txt 存在,已刪除。"); }else{ f.createNewFile();//在當前目錄下建立一個名為File.txt的文件 out.println(path + "\\File.txt 不存在,已建立。");//輸出目前所在的目錄路徑 } %>
目錄的建立/檢查與刪除 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>目錄的建立/檢查與刪除</title> </head> <body> <% String path=request.getRealPath(""); path=path + "\\Sub";//將要建立的目錄路徑 File d=new File(path);//建立代表Sub目錄的File對象,并得到它的一個引用 if(d.exists()){//檢查Sub目錄是否存在 d.delete(); out.println("Sub目錄存在,已刪除"); }else{ d.mkdir();//建立Sub目錄 out.println("Sub目錄不存在,已建立"); } %> </body> </html>
如何在JSP中處理虛擬目錄 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>JSP中如何處理虛擬目錄</title> </head> <body> 取得虛擬目錄對應的磁盤路徑<br> Web站點主目錄的位置為<font color=#ff0000><%=request.getRealPath("/")%></font><br> JSP網頁所在的目錄位置<font color=#ff0000><%=request.getRealPath("./")%></font><br> JSP網頁所在目錄上一層目錄的位置<font color=#ff0000><%=request.getRealPath("../")%></font><br> </body> </html>
文件屬性的取得 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.util.Date,java.io.*"%> <html> <head> <title>文件屬性的取得</title> </head> <body> <% String path=request.getRealPath("/"); File f=new File(path,"ReadData.txt"); if(f.exists()){ %> <%=f.getName()%>的屬性如下:<br><br> 文件長度為:<%=f.length()%> <%=f.isFile()?"是文件":"不是文件"%><br> <%=f.isDirectory()?"是目錄":"不是目錄"%><br> <%=f.canRead()?"可讀取":"不可讀取"%><br> <%=f.canWrite()?"可寫入":"不可寫入"%><br> <%=f.isHidden()?"是隱藏文件":"不是隱藏文件"%><br> 文件的最后修改日期為:<%=new Date(f.lastModified())%><br> <% }else{ f.createNewFile();//在當前目錄下建立一個名為ReaData.txt的文件 %> <%=f.getName()%>的屬性如下:<br><br> 文件長度為:<%=f.length()%> <%=f.isFile()?"是文件":"不是文件"%><br> <%=f.isDirectory()?"是目錄":"不是目錄"%><br> <%=f.canRead()?"可讀取":"不可讀取"%><br> <%=f.canWrite()?"可寫入":"不可寫入"%><br> <%=f.isHidden()?"是隱藏文件":"不是隱藏文件"%><br> 文件的最后修改日期為:<%=new Date(f.lastModified())%><br> <% } %> </body> </html>
取出目錄中文件的方法 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>取出目錄中文件的方法--列出目錄中的文件</title> </head> <body> <% String path=request.getRealPath("/"); File d=new File(path);//建立當前目錄中文件的File對象 File list[]=d.listFiles();//取得代表目錄中所有文件的File對象數組 out.println("<font color=#ff0000>" + path + "目錄下的文件:</font><br>"); for(int i=0;i<list.length;i++){ if(list<I>.isFile()){ out.println(list<I>.getName() + "<br>"); } } out.println("<br><font color=#ff0000>" + path + "目錄下的目錄:</font><br>"); for(int i=0;i<list.length;i++){ if(list<I>.isDirectory()){ out.println(list<I>.getName() + "<br>"); } } %> </body> </html>
判斷是否為空白文件 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>判斷是否為空白文件</title> </head> <body> <% String path=request.getRealPath("/"); out.println(path); FileReader fr=new FileReader(path + "\\AtEnd.txt");//建立FileReader對象,并實例化為fr //對FileReader類生成的對象使用read()方法,可以從字符流中讀取下一個字符。 if(fr.read()==-1)//判斷是否已讀到文件的結尾 { out.print("AtEnd.txt文件中沒有數據<br>"); }else{ out.println("AtEnd.txt文件中有數據"); } fr.close(); %> </body> </html>
讀取所有的文件數據 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*,java.lang.*"%> <html> <head> <title>讀取所有的文件數據</title> </head> <body> <% String path=request.getRealPath("."); FileReader fr=new FileReader(path + "\\ReadData.txt"); //關鍵在于讀取過程中,要判斷所讀取的字符是否已經到了文件的末尾,并且這個字符是不是文件中的斷行符,即判斷該字符值是否為13。 int c=fr.read();//從文件中讀取一個字符 //判斷是否已讀到文件結尾 while(c!=-1){ out.print((char)c);//輸出讀到的數據 c=fr.read();//從文件中繼續讀取數據 if(c==13){//判斷是否為斷行字符 out.print("<br>");//輸出分行標簽 fr.skip(1);//略過一個字符 //c=fr.read();//讀取一個字符 } } fr.close(); %> </body> </html>
一行一行讀取數據 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>文件讀取</title> </head> <body> <% String path=request.getRealPath("");//取得當前目錄的路徑 FileReader fr=new FileReader(path + "\\file\\inc\\t.txt");//建立FileReader對象,并實例化為fr BufferedReader br=new BufferedReader(fr);//建立BufferedReader對象,并實例化為br String Line=br.readLine();//從文件讀取一行字符串 //判斷讀取到的字符串是否不為空 while(Line!=null){ out.println(Line + "<br>");//輸出從文件中讀取的數據 Line=br.readLine();//從文件中繼續讀取一行數據 } br.close();//關閉BufferedReader對象 fr.close();//關閉文件 %> </body> </html>
略過文件中的字符不讀取 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>略過字節不讀取</title> </head> <body> <% String path=request.getRealPath("."); FileReader fr=new FileReader(path + "\\ReadData.txt"); fr.skip(2);//跳過2個字節 int c=fr.read();//讀取一個字節 while(c!=-1){ out.print((char)c); c=fr.read(); } fr.close(); %> </body> </html>
將數據寫入文件 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>將數據寫入文件</title> </head> <body> <% String path=request.getRealPath("."); FileWriter fw=new FileWriter(path + "\\WriteData.txt");//建立FileWriter對象,并實例化fw //將字符串寫入文件 fw.write("大家好!"); fw.write("本書是《JSP編程技巧》"); fw.write("請多多指教!"); fw.write("email:stride@sina.com"); fw.close();
FileReader fr=new FileReader(path + "\\WriteData.txt"); BufferedReader br=new BufferedReader(fr);//建立BufferedReader對象,并實例化為br String Line=br.readLine(); //讀取一行數據 out.println(Line + "<br>"); br.close();//關閉BufferedReader對象 fr.close(); %> </body> </html>
將寫入文件的數據分行 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>將寫入文件的數據分行</title> </head> <body> <% String path=request.getRealPath("."); FileWriter fw=new FileWriter(path + "\\WriteData.txt"); BufferedWriter bw=new BufferedWriter(fw); bw.write("大家好!"); bw.write("本書是《JSP編程技巧》。"); bw.newLine();//斷行 bw.write("請多多指教!"); bw.newLine();//斷行 bw.write("email: stride@sina.com"); bw.flush();//將數據更新至文件 fw.close();//關閉文件流 out.println("寫入文件內容為:<br>"); FileReader fr=new FileReader(path + "\\WriteData.txt"); BufferedReader br=new BufferedReader(fr); String Line=br.readLine();//讀取一行數據 while(Line!=null){ out.println(Line + "<br>"); Line=br.readLine(); } fr.close(); %> </body> </html> 如何將數據追加寫入到文件 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>將寫入文件的數據分行</title> </head> <body> <% String path=request.getRealPath("."); RandomAccessFile rf=new RandomAccessFile(path + "\\WriteData.txt","rw");//定義一個類RandomAccessFile的對象,并實例化 rf.seek(rf.length());//將指針移動到文件末尾 rf.writeBytes("\nAppend a line to the file!"); rf.close();//關閉文件流 out.println("寫入文件內容為:<br>"); FileReader fr=new FileReader(path + "\\WriteData.txt"); BufferedReader br=new BufferedReader(fr);//讀取文件的BufferedRead對象 String Line=br.readLine(); while(Line!=null){ out.println(Line + "<br>"); Line=br.readLine(); } fr.close();//關閉文件 %> </body> </html></I></I></I></I>
JDK1.5 令我們期待很久,可是當他發布的時候卻更換版本號為5.0。這說明Java已經有大幅度的變化。本文將講解JDK5.0支持的新功能-----Java的 泛型. 1、Java泛型 其實Java的泛型就是創建一個用類型作為參數的類。就象我們寫類的方法一樣,方法是這樣的 method( String str1,String str2 ),方法中參數str1、str2的值是可變的。而泛型也是一樣的,這樣寫 class Java_Generics<K,V>,這里邊的K和V就象方法中的參數str1和str2,也是可變。下面看看例子:
//code list 1 import Java.util.Hashtable; class TestGen0<K,V>{ public Hashtable<K,V> h=new Hashtable<K,V>(); public void put(K k, V v) { h.put(k,v); } public V get(K k) { return h.get(k); } public static void main(String args[]){ TestGen0<String,String> t=new TestGen0<String,String>(); t.put("key", "value"); String s=t.get("key"); System.out.println(s); } } |
正確輸出:value 這只是個例子(Java中集合框架都泛型化了,這里費了2遍事.),不過看看是不是創建一個用類型作為參數的類,參數是K,V,傳入的“值”是String類型。這個類他沒有特定的待處理型別,以前我們 定義好了一個類,在輸入輸入參數有所固定,是什么型別的有要求,但是現在編寫程序,完全可以不制定參數的類型,具體用的時候來確定,增加了程序的通用性,像是一個 模板。 呵呵,類似C++的模板(類似)。 1.1. 泛型通配符 下面我們先看看這些程序:
//Code list 2 void TestGen0Medthod1(List l) { for (Object o : l) System.out.println(o); } |
看看這個方法有沒有異議,這個方法會通過編譯的,假如你傳入String,就是這樣List<String>。 接著我們調用它,問題就出現了,我們將一個List<String>當作List傳給了方法,JVM會給我們一個警告,說這個破壞了 類型安全,因為從List中返回的都是Object類型的,而讓我們再看看下面的方法。
//Code list 3 void TestGen0Medthod1(List<String> l) { for (Object o : l) System.out.println(o); } |
因為這里的List<String>不是List<Object>的子類,不是String與Object的關系,就是說List<String>不隸屬于list<Object>,他們不是繼承關系,所以是不行的,這里的extends是表示限制的。 類型通配符是很神奇的,List<?>這個你能為他做什么呢?怎么都是“?”,它似乎不確定,他總不能返回一個?作為類型的數據吧,是啊他是不會返回一個“?”來問程序員的?JVM會做簡單的思考的,看看代碼吧,更直觀些。
//code list 4 List<String> l1 = new ArrayList<String>(); li.add(“String”); List<?> l2 = l1; System.out.println(l1.get(0)); |
這段代碼沒問題的,l1.get(0)將返回一個Object。 1.2. 編寫泛型類要注意: 1) 在定義一個泛型類的時候,在 “<>”之間定義形式類型參數,例如:“class TestGen<K,V>”,其中“K” , “V”不代表值,而是表示類型。 2) 實例化泛型對象的時候,一定要在類名后面指定類型參數的值(類型),一共要有兩次書寫。例如: TestGen<String,String> t=new TestGen<String,String>(); 3) 泛型中<K extends Object>,extends并不代表繼承,它是類型范圍限制。 2、泛型與數據類型轉換 2.1. 消除類型轉換 上面的例子大家看到什么了,數據類型轉換的代碼不見了。在以前我們經常要書寫以下代碼,如:
//code list 5 import Java.util.Hashtable; class Test { public static void main(String[] args) { Hashtable h = new Hashtable(); h.put("key", "value"); String s = (String)h.get("key"); System.out.println(s); } } |
這個我們做了類型轉換,是不是感覺很煩的,并且強制類型轉換會帶來潛在的危險,系統可能會拋一個ClassCastException異常信息。在JDK5.0中我們完全可以這么做,如:
//code list 6 import Java.util.Hashtable; class Test { public static void main(String[] args) { Hashtable<String,Integer> h = new Hashtable<String,Integer> (); h.put("key", new Integer(123)); int s = h.get("key").intValue(); System.out.println(s); } } |
這里我們使用泛化版本的HashMap,這樣就不用我們來編寫類型轉換的代碼了,類型轉換的過程交給編譯器來處理,是不是很方便,而且很安全。上面是String映射到String,也可以將Integer映射為String,只要寫成HashTable<Integer,String> h=new HashTable<Integer,String>();h.get(new Integer(0))返回value。果然很方便。 2.2 自動解包裝與自動包裝的功能 從上面有沒有看到有點別扭啊,h.get(new Integer(123))這里的new Integer(123);好煩的,在JDK5.0之前我們只能忍著了,現在這種問題已經解決了,請看下面這個方法。我們傳入一個int這一基本型別,然后再將i的值直接添加到List中,其實List是不能儲存基本型別的,List中應該存儲對象,這里編譯器將int包裝成Integer,然后添加到List中去。接著我們用List.get(0);來檢索數據,并返回對象再將對象解包裝成int。恩,JDK5.0給我們帶來更多方便與安全。
//Code list 7 public void autoBoxingUnboxing(int i) { ArrayList<Integer> L= new ArrayList<Integer>(); L.add(i); int a = L.get(0); System.out.println("The value of i is " + a); } |
2.3 限制泛型中類型參數的范圍 也許你已經發現在code list 1中的TestGen<K,V>這個泛型類,其中K,V可以是任意的型別。也許你有時候呢想限定一下K和V當然范圍,怎么做呢?看看如下的代碼:
//Code list 8 class TestGen2<K extents String,V extends Number> { private V v=null; private K k=null; public void setV(V v){ this.v=v; } public V getV(){ return this.v; } public void setK(K k){ this.k=k; } public V getK(){ return this.k; } public static void main(String[] args) { TestGen2<String,Integer> t2=new TestGen2<String,Integer>(); t2.setK(new String("String")); t2.setV(new Integer(123)); System.out.println(t2.getK()); System.out.println(t2.getV()); } } |
上邊K的范圍是<=String ,V的范圍是<=Number,注意是“<=”,對于K可以是String的,V當然也可以是Number,也可以是Integer,Float,Double,Byte等。看看下圖也許能直觀些請看上圖A是上圖類中的基類,A1,A2分別是A的子類,A2有2個子類分別是A2_1,A2_2。 然后我們定義一個受限的泛型類class MyGen<E extends A2>,這個泛型的范圍就是上圖中蘭色部分。 這個是單一的限制,你也可以對型別多重限制,如下:
class C<T extends Comparable<? super T> & Serializable> |
我們來分析以下這句,T extends Comparable這個是對上限的限制,Comparable< super T>這個是下限的限制,Serializable是第2個上限。一個指定的類型參數可以具有一個或多個上限。具有多重限制的類型參數可以用于訪問它的每個限制的方法和域。 2.4. 多態方法
//Code list 9 class TestGen { <T extends Object> public static List<T> make(T first) { return new List<T>(first); } } |
摘要: 摘要
Reflection 是Java被視為動態(或準動態)語言的一個關鍵性質。這個機制允許程序在運行時透過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifiers(諸如public, static 等等)、superclass(例如Object)、實現之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于... 閱讀全文
首先它需要一個裝箱單,把你的所有資源文件包括html,img文件還有WEB-INF文件夾等等。然后在這個文件夾內建一個新的文件夾META-INF。在META-INF文件夾內建一個txt文件,輸入Manifest-Version: 1.0并保存為MANIFEST.MF。然后將你這個文件夾壓,注意壓成zip格式。完成后將后綴名改為war就可以了。 你也可以通過相關工具打包,比如JBuilder。 關于Tomcat發布和普通的web發布一樣。 嘗試上面方法沒成功 我把jar.exeCOPY到目錄裡用下面方法可以了,
(1):打包war :進入 工程 應用的根目錄,
比如: <CATALINA_HOME>/webapps/myjspweb ;
(2)把整個 web 應用打包為 myjspwar.war 文件,命令如下: jar cvf myjspweb.war *.*
(3):解包: jar xvf helloapp.war
1.document.write(""); 輸出語句 2.JS中的注釋為// 3.傳統的HTML文檔順序是:document->html->(head,body) 4.一個瀏覽器窗口中的DOM順序是:window->(navigator,screen,history,location,document) 5.得到表單中元素的名稱和值:document.getElementById("表單中元素的ID號").name(或value) 6.一個小寫轉大寫的JS: document.getElementById("output").value = document.getElementById("input").value.toUpperCase(); 7.JS中的值類型:String,Number,Boolean,Null,Object,Function 8.JS中的字符型轉換成數值型:parseInt(),parseFloat() 9.JS中的數字轉換成字符型:(""+變量) 10.JS中的取字符串長度是:(length) 11.JS中的字符與字符相連接使用+號. 12.JS中的比較操作符有:==等于,!=不等于,>,>=,<.<= 13.JS中聲明變量使用:var來進行聲明 14.JS中的判斷語句結構:if(condition){}else{} 15.JS中的循環結構:for([initial expression];[condition];[upadte expression]) {inside loop} 16.循環中止的命令是:break 17.JS中的函數定義:function functionName([parameter],...){statement[s]} 18.當文件中出現多個form表單時.可以用document.forms[0],document.forms[1]來代替. 19.窗口:打開窗口window.open(), 關閉一個窗口:window.close(), 窗口本身:self 20.狀態欄的設置:window.status="字符"; 21.彈出提示信息:window.alert("字符"); 22.彈出確認框:window.confirm(); 23.彈出輸入提示框:window.prompt(); 24.指定當前顯示鏈接的位置:window.location.href="URL" 25.取出窗體中的所有表單的數量:document.forms.length 26.關閉文檔的輸出流:document.close(); 27.字符串追加連接符:+= 28.創建一個文檔元素:document.createElement(),document.createTextNode() 29.得到元素的方法:document.getElementById() 30.設置表單中所有文本型的成員的值為空: var form = window.document.forms[0] for (var i = 0; i<form.elements.length;i++){ if (form.elements[i].type == "text"){ form.elements[i].value = ""; } } 31.復選按鈕在JS中判斷是否選中:document.forms[0].checkThis.checked (checked屬性代表為是否選中返回TRUE或FALSE) 32.單選按鈕組(單選按鈕的名稱必須相同):取單選按鈕組的長度document.forms[0].groupName.length 33.單選按鈕組判斷是否被選中也是用checked. 34.下拉列表框的值:document.forms[0].selectName.options[n].value (n有時用下拉列表框名稱加上.selectedIndex來確定被選中的值) 35.字符串的定義:var myString = new String("This is lightsword"); 36.字符串轉成大寫:string.toUpperCase(); 字符串轉成小寫:string.toLowerCase(); 37.返回字符串2在字符串1中出現的位置:String1.indexOf("String2")!=-1則說明沒找到. 38.取字符串中指定位置的一個字符:StringA.charAt(9); 39.取出字符串中指定起點和終點的子字符串:stringA.substring(2,6); 40.數學函數:Math.PI(返回圓周率),Math.SQRT2(返回開方),Math.max(value1,value2)返回兩個數中的最在值,Math.pow(value1,10)返回value1的十次方,Math.round(value1)四舍五入函數,Math.floor(Math.random()*(n+1))返回隨機數 41.定義日期型變量:var today = new Date(); 42.日期函數列表:dateObj.getTime()得到時間,dateObj.getYear()得到年份,dateObj.getFullYear()得到四位的年份,dateObj.getMonth()得到月份,dateObj.getDate()得到日,dateObj.getDay()得到日期幾,dateObj.getHours()得到小時,dateObj.getMinutes()得到分,dateObj.getSeconds()得到秒,dateObj.setTime(value)設置時間,dateObj.setYear(val)設置年,dateObj.setMonth(val)設置月,dateObj.setDate(val)設置日,dateObj.setDay(val)設置星期幾,dateObj.setHours設置小時,dateObj.setMinutes(val)設置分,dateObj.setSeconds(val)設置秒 [注意:此日期時間從0開始計] 43.FRAME的表示方式: [window.]frames[n].ObjFuncVarName,frames["frameName"].ObjFuncVarName,frameName.ObjFuncVarName 44.parent代表父親對象,top代表最頂端對象 45.打開子窗口的父窗口為:opener 46.表示當前所屬的位置:this 47.當在超鏈接中調用JS函數時用:(Javascript:)來開頭后面加函數名 48.在老的瀏覽器中不執行此JS:<!-- //--> 49.引用一個文件式的JS:<script type="text/Javascript" src="aaa.js"></script> 50.指定在不支持腳本的瀏覽器顯示的HTML:<noscript></noscript> 51.當超鏈和ONCLICK事件都有時,則老版本的瀏覽器轉向a.html,否則轉向b.html.例:<a href="a.html" onclick="location.href='b.html';return false">dfsadf</a> 52.JS的內建對象有:Array,Boolean,Date,Error,EvalError,Function,Math,Number,Object,RangeError,ReferenceError,RegExp,String,SyntaxError,TypeError,URIError 53.JS中的換行:\n 54.窗口全屏大小:<script>function fullScreen(){ this.moveTo(0,0);this.outerWidth=screen.availWidth;this.outerHeight=screen.availHeight;}window.maximize=fullScreen;</script> 55.JS中的all代表其下層的全部元素
56.JS中的焦點順序:document.getElementByid("表單元素").tabIndex = 1 57.innerHTML的值是表單元素的值:如<p id="para">"how are <em>you</em>"</p>,則innerHTML的值就是:how are <em>you</em> 58.innerTEXT的值和上面的一樣,只不過不會把<em>這種標記顯示出來. 59.contentEditable可設置元素是否可被修改,isContentEditable返回是否可修改的狀態. 60.isDisabled判斷是否為禁止狀態.disabled設置禁止狀態 61.length取得長度,返回整型數值 62.addBehavior()是一種JS調用的外部函數文件其擴展名為.htc 63.window.focus()使當前的窗口在所有窗口之前. 64.blur()指失去焦點.與FOCUS()相反. 65.select()指元素為選中狀態. 66.防止用戶對文本框中輸入文本:onfocus="this.blur()" 67.取出該元素在頁面中出現的數量:document.all.tags("div(或其它HTML標記符)").length 68.JS中分為兩種窗體輸出:模態和非模態.window.showModaldialog(),window.showModeless() 69.狀態欄文字的設置:window.status='文字',默認的狀態欄文字設置:window.defaultStatus = '文字.'; 70.添加到收藏夾:external.AddFavorite("http://www.xrss.cn","jaskdlf"); 71.JS中遇到腳本錯誤時不做任何操作:window.onerror = doNothing; 指定錯誤句柄的語法為:window.onerror = handleError; 72.JS中指定當前打開窗口的父窗口:window.opener,支持opener.opener...的多重繼續. 73.JS中的self指的是當前的窗口 74.JS中狀態欄顯示內容:window.status="內容" 75.JS中的top指的是框架集中最頂層的框架 76.JS中關閉當前的窗口:window.close(); 77.JS中提出是否確認的框:if(confirm("Are you sure?")){alert("ok");}else{alert("Not Ok");} 78.JS中的窗口重定向:window.navigate("http://www.sina.com.cn"); 79.JS中的打印:window.print() 80.JS中的提示輸入框:window.prompt("message","defaultReply"); 81.JS中的窗口滾動條:window.scroll(x,y) 82.JS中的窗口滾動到位置:window.scrollby 83.JS中設置時間間隔:setInterval("expr",msecDelay)或setInterval(funcRef,msecDelay)或setTimeout 84.JS中的模態顯示在IE4+行,在NN中不行:showModalDialog("URL"[,arguments][,features]); 85.JS中的退出之前使用的句柄:function verifyClose(){event.returnValue="we really like you and hope you will stay longer.";}} window.onbeforeunload=verifyClose; 86.當窗體第一次調用時使用的文件句柄:onload() 87.當窗體關閉時調用的文件句柄:onunload() 88.window.location的屬性: protocol(http:),hostname(www.example.com),port(80),host(www.example.com:80),pathname("/a/a.html"),hash("#giantGizmo",指跳轉到相應的錨記),href(全部的信息) 89.window.location.reload()刷新當前頁面. 89-1.parent.location.reload()刷新父親對象(用于框架) 89-2.opener.location.reload()刷新父窗口對象(用于單開窗口) 89-3.top.location.reload()刷新最頂端對象(用于多開窗口) 90.window.history.back()返回上一頁,window.history.forward()返回下一頁,window.history.go(返回第幾頁,也可以使用訪問過的URL) 91.document.write()不換行的輸出,document.writeln()換行輸出 92.document.body.noWrap=true;防止鏈接文字折行. 93.變量名.charAt(第幾位),取該變量的第幾位的字符. 94."abc".charCodeAt(第幾個),返回第幾個字符的ASCii碼值. 95.字符串連接:string.concat(string2),或用+=進行連接 96.變量.indexOf("字符",起始位置),返回第一個出現的位置(從0開始計算) 97.string.lastIndexOf(searchString[,startIndex])最后一次出現的位置. 98.string.match(regExpression),判斷字符是否匹配. 99.string.replace(regExpression,replaceString)替換現有字符串. 100.string.split(分隔符)返回一個數組存儲值. 101.string.substr(start[,length])取從第幾位到指定長度的字符串. 102.string.toLowerCase()使字符串全部變為小寫. 103.string.toUpperCase()使全部字符變為大寫. 104.parseInt(string[,radix(代表進制)])強制轉換成整型. 105.parseFloat(string[,radix])強制轉換成浮點型. 106.isNaN(變量):測試是否為數值型. 107.定義常量的關鍵字:const,定義變量的關鍵字:var
|