1. 程式人生 > >自己用的C#基礎學習筆記(二)——C#面向物件(2)

自己用的C#基礎學習筆記(二)——C#面向物件(2)

第十一天

1.1 string stringbuffer stringbulider

1.三者在執行速度方面的比較:StringBuilder >  StringBuffer  >  String

2.String <StringBufferStringBuilder)的原因

String:字串常量

StringBuffer:字元創變數

StringBuilder:字元創變數

  從上面的名字可以看到,String字元創常量,也就是不可改變的物件。對於這句話的理解你可能會產生這樣一個疑問,比如這段程式碼:

1 String s = "abcd";
2 s = s+1;
3 System.out.print(s);// result : abcd1

  我們明明就是改變了String型的變數s的,為什麼說是沒有改變呢? 其實這是一種欺騙,JVM是這樣解析這段程式碼的:首先建立物件s,賦予一個abcd,然後再建立一個新的物件s用來    

執行第二行程式碼,也就是說我們之前物件s並沒有變化,所以我們說String型別是不可改變的物件了,由於這種機制,每當用String操作字串時,實際上是在不斷的建立新的物件,而原來的物件就會變為垃圾被GC回收掉,可想而知這樣執行效率會有多底。

  而StringBufferStringBuilder就不一樣了,他們是字串變數,是可改變的物件,每當我們用它們對字串做操作時,實際上是在一個物件上操作的,這樣就不會像

String一樣建立一些而外的物件進行操作了,當然速度就快了。

3.一個特殊的例子:

1 String str = “This is only a” + “ simple” + “ test”;
3 StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

  你會很驚訝的發現,生成str物件的速度簡直太快了,而這個時候StringBuffer居然速度上根本一點都不佔優勢。其實這是JVM的一個把戲,實際上:

String str = “This is only a” + “ simple” + “test”;

  其實就是:

String str = “This is only a simple test”;

  所以不需要太多的時間了。但大家這裡要注意的是,如果你的字串是來自另外的String物件的話,速度就沒那麼快了,譬如:

String str2 = “This is only a”;

String str3 = “ simple”;

String str4 = “ test”;

String str1 = str2 +str3 + str4;

這時候JVM會規規矩矩的按照原來的方式去做。

4.StringBuilderStringBuffer

StringBuilder:執行緒非安全的

StringBuffer:執行緒安全的

當我們在字串緩衝去被多個執行緒使用是,JVM不能保證StringBuilder的操作是安全的,雖然他的速度最快,但是可以保證StringBuffer是可以正確操作的。當然大多數情況下就是我們是在單執行緒下進行的操作,所以大多數情況下是建議用StringBuilder而不用StringBuffer的,就是速度的原因。

對於三者使用的總結:

1.如果要操作少量的資料用 = String

2.單執行緒操作字串緩衝區 下操作大量資料 = StringBuilder

3.多執行緒操作字串緩衝區 下操作大量資料 = StringBuffer

1.2 執行緒安全與不安全

執行緒安全就是多執行緒訪問時,採用了加鎖機制,當一個執行緒訪問該類的某個資料時,進行保護,其他執行緒不能進行訪問直到該執行緒讀取完,其他執行緒才可使用。不會出現資料不一致或者資料汙染。 執行緒不安全就是不提供資料訪問保護,有可能出現多個執行緒先後更改資料造成所得到的資料是髒資料。

執行緒安全問題都是由全域性變數靜態變數引起的。

若每個執行緒中對全域性變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的;若有多個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則的話就可能影響執行緒安全。

比如一個 ArrayList 類,在新增一個元素的時候,它可能會有兩步來完成:1. Items[Size] 的位置存放此元素;2. 增大 Size 的值。

單執行緒執行的情況下,如果 Size = 0,新增一個元素後,此元素在位置 0,而且 Size=1

而如果是在多執行緒情況下,比如有兩個執行緒,執行緒 A 先將元素存放在位置 0。但是此時 CPU 排程執行緒A暫停,執行緒 B 得到執行的機會。執行緒B也向此 ArrayList 新增元素,因為此時 Size 仍然等於 0 (注意哦,我們假設的是新增一個元素是要兩個步驟哦,而執行緒A僅僅完成了步驟1),所以執行緒B也將元素存放在位置0。然後執行緒A和執行緒B都繼續執行,都增加 Size 的值。

那好,我們來看看 ArrayList 的情況,元素實際上只有一個,存放在位置 0,而 Size 卻等於 2。這就是執行緒不安全了。

1.3 字串操作函式

1.3.1 獲取長度 字串.Length

String s = “232”;s.Length;

1.3.2 大小寫轉換 str.ToUpper()大寫  str.ToLoewr()小寫

1.3.3 判斷是否相等 str.Equals()

返回布林值,括號加逗號可以看到過載。

第二個引數:StringComparison.OrdinalIgnoreCase是不區分大小寫,預設不寫區分。StringComparison是列舉型別。例如:str.Equals(“fsaff”, StringComparison.OrdinalIgnoreCase);

1.3.4 包含 str.Contains(“比較字串”)

返回布林值。

1.3.5 是否以某個字串開始 str.StartsWith(“比較字串”)

返回布林值

1.3.6 是否以某個字串結束 str.EndsWith(“比較字串”)

返回布林值

1.3.7 分割字串 str.Split(char陣列,StringSplitOptions.RemoveEmptyEntries);

第二個引數是處理空白字元(用於以空白字串分割)。返回string型別的陣列。

字串會根據Char型別的陣列中的字元來分割自己,且分割後的字元不包含char字元本身。

1.3.8 字串與char陣列轉換

字串本身是一個char型別的只讀陣列.並且使用str[n]的方式讀取的資料型別是char,判斷時需要用char型別來判斷,否則會出錯。

Char[] chs = str.ToCharArray();

Str = new string(chs);

1.3.9 字串在某字串中的開始位置和結束位置

Str.IndexOf(“比較字串,開始數字,可以不寫,預設從0開始找)

返回字串所在索引數,沒找到返回-1,索引從0開始

例如:str.IndexOf(“fsd”,6);從第六個開始找

Str.LastIndexOf(“比較字串,開始數字,可以不寫,預設從最後開始找)

倒著找,用法和上面一樣

1.3.10 去掉空格

String str1 = Str.Trim();去掉前後空格,不能去中間的

String str1 =  Str.TrimEnd();去掉後面的空格

String str1 =  Str.TrimStart();去掉前面的空格

返回字串,必須用字串變數接收。

1.3.11 替換

Str.Replace(被替換字串,替換成的內容);舉例:

Str.Replace(“aa”,”bb”);

1.3.12 判斷是否為空串或空字串

空字串雖然什麼都沒存,但是佔用空間。Str=””;

空間null不佔空間。Str=null; 可以用來釋放空間

String.IsNullOrEmpty();

返回值為布林值。

1.3.13 連線字串 string.Join()

String s = stirng.Join(“|”,”dafsd”,”fdsfa”);

第一個是連線字元,後面是連線內容,後面可以用陣列表示,int陣列也可以

1.3.14 擷取字串

String ss = s.SubString(1);從第一字元開始擷取到最後

String ss= s.SubString(1,3);從字串的第一個位置開始擷取,擷取3個字元。

1.3.15 格式化字串

String str = String.Format();按想要的格式輸出。返回字串

格式字串形式內容:

1、 格式化貨幣(跟系統環境有關,中文人民幣,英文美元)

String.Format(“{0:C}”,0.2)   結果¥0.20(英文系統$0.20

預設保留兩位小數,可以指定:

String.Format(“{0:C1}”,0.2222)  結果¥0.2(自動四捨五入)

還可以一次性格式化多個:

String.Format(“市場價:{0:C},優惠價{1:C3}”,23.15,19.82);

2、 格式化十進位制的數字(格式化成固定的位數,位數不能少於未格式化前,只支援整型)

String.Format(“{0:D3}”,23);  結果023

String.Format(“{0:D2}”,1232);  結果1232(2只能代表格式化的最小位數,不會自己取捨)

3、 用分號隔數字,並指定小數位數

String.Format(“{0:N}”,14200); 結果14,200.00(預設為兩位小數)

String.Format(“{0:D3}”,14200.2345); 142.235(自動四捨五入)

4、格式化百分比

String.Format(“{0:P}”,0.24583); 24.58%預設兩位小數

String.Format(“{0:P1}”,0.24583); 24.6%四捨五入

5、零佔位符和數字佔位符效果和第2條類似,但支援整數和小數

String.Format(“{0:0000.00}”,123456.344);123456.34

String.Format(“{0:0000.00}”,123.4455);0123.45

String.Format(“{0:####.##}”,123445.5645); 123445.56

String.Format(“{0:####.#}”,194.0394);194

空格佔位符

String.Format(“{0,-50}”,”abcde”); //格式化成50個字元,原字元左對齊,不足則補充空格

String.Format(“{0,50}”,”abcde”); //格式化成50個字元,原字元右對齊,不足則補充空格

6、日期格式化

String.Format(“{0:d}”,System.DateTime.Now);2009-3-2

String.Format(“{0:D}”,System.DateTime.Now);2009320

String.Format(“{0:f}”,System.DateTime.Now);200932015:37

String.Format(“{0:F}”,System.DateTime.Now); 200932015:37:52

String.Format(“{0:g}”,System.DateTime.Now); 2009-3-2 15:37

String.Format(“{0:G}”,System.DateTime.Now); 2009-3-2 15:37:27

String.Format(“{0:m}”,System.DateTime.Now);320

String.Format(“{0:t}”,System.DateTime.Now);15:41

String.Format(“{0:T}”,System.DateTime.Now);15:41:50

1.4 陣列類(陣列操作函式)

屬性

1

IsFixedSize獲取一個值,該值指示陣列是否帶有固定大小。

2

IsReadOnly獲取一個值,該值指示陣列是否只讀。

3

Length獲取一個 32 位整數,該值表示所有維度的陣列中的元素總數。

4

LongLength獲取一個 64 位整數,該值表示所有維度的陣列中的元素總數。

5

Rank獲取陣列的秩(維度)。

下表列出了 Array 類中一些最常用的方法:

序號

方法 & 描述

1

Clear根據元素的型別,設定陣列中某個範圍的元素為零、為 false 或者為 null

2

Copy(Array, Array, Int32)從陣列的第一個元素開始複製某個範圍的元素到另一個數組的第一個元素位置。長度由一個 32 位整數指定。

3

CopyTo(Array, Int32)從當前的一維陣列中複製所有的元素到一個指定的一維陣列的指定索引位置。索引由一個 32 位整數指定。

4

GetLength獲取一個 32 位整數,該值表示指定維度的陣列中的元素總數。

5

GetLongLength獲取一個 64 位整數,該值表示指定維度的陣列中的元素總數。

6

GetLowerBound獲取陣列中指定維度的下界。

7

GetType獲取當前例項的型別。從物件(Object)繼承。

8

GetUpperBound獲取陣列中指定維度的上界。

9

GetValue(Int32)獲取一維陣列中指定位置的值。索引由一個 32 位整數指定。

10

IndexOf(Array, Object)搜尋指定的物件,返回整個一維陣列中第一次出現的索引。

11

Reverse(Array)逆轉整個一維陣列中元素的順序。

12

SetValue(Object, Int32)給一維陣列中指定位置的元素設定值。索引由一個 32 位整數指定。

13

Sort(Array)使用陣列的每個元素的 IComparable 實現來排序整個一維陣列中的元素。

14

ToString返回一個表示當前物件的字串。從物件(Object)繼承。

1.5 ArrayList集合(動態陣列) (不推薦用)

1.5.1 ArrayList集合

長度隨便,型別隨便,集合的元素都是object型別,任何元素新增到集合中後,都會被裝箱成object型別

使用前,必須引用名稱空間using System.Collections;

ArrayList list = new ArrayList();

List.Add(2);

List.Add(“sadfsda”);list.Add(物件);

Add();可以新增任意型別的變數值。

任何一個數據型別都可以使用is來判斷,判斷後都可以使用強制轉換。例如,物件,陣列,結構體等。

If(List[i] is int[]){

For(int j=0;j<((int[])list[i]).Length;i++){

Cw(((int[])list[i])[j]);

}

}

1.5.2 ArrayList方法(自己學習)

Add();新增元素

AddRange();可以將集合的元素直接新增的集合中,主要是集合和陣列中的元素,用此函式會直接新增元素,不會出現輸出只顯示名稱空間的情況

Remove(“元素值”);移除指定的元素。例如:list.Remove(3);移除值為3的元素

RemoveAt();移除下標的元素。例如:list.RemoveAt(0);移除第一個元素

List. RemoveRange();用於刪除一批元素,通過指定開始的索引和刪除的數量來刪除List.Insert(位置,);插入一個元素,例如:list.Insert(3,”ddf”);第四個(下標為3的)就會變成ddf

List.InsertRange(位置,陣列元素);插入一個集合

List.clear();移除集合中所有元素。

List.Reverse();反轉

List.Sort ();升序排序

List.Contains();集合中是否包含某個元素,例如list.Contains(2);判斷集合中是否包含2

TrimSize方法

這個方法用於將ArrayList固定到實際元素的大小,當動態陣列元素確定不在新增的時候,可以呼叫這個方法來釋放空餘的記憶體。

ToArray方法

這個方法把ArrayList的元素Copy到一個新的陣列中。Int32[] values = (Int32[])List.ToArray(typeof(Int32));

Int32[] values = new Int32[List.Count];

List.CopyTo(values);

1.6 鍵值對集合HashTable雜湊表(類似PHP的字串陣列)

Hashtable中的元素儲存在DictionaryEntry物件

名稱空間和ArrayList一樣,using Collections;

定義:Hashtable t = new Hashtable();

鍵是唯一的,通過鍵找值

新增:t.Add(“”,””);t.Add(true,false);t.Add(1.5f,”aa”);重複鍵使用add新增會報錯。

或者 t[0] = 5;//新增一個鍵為0值為5的元素,t[“sdaf”] = “safs”;相同鍵會覆蓋值

新增鍵值對沒有順序。

1.6.1 鍵值對的遍歷

Foreach(var ii in t.Keys){

Console.WriteLine(“{0},值{1}”,ii,t[ii]);

}

Foreach(DictionaryEntry ii in t){

Console.WriteLine(“{0},值{1}”,ii.Key,ii.Value);

}

1.6.2 ArrayList長度

List.count 集合中實際存在的元素個數

List.Capacity 集合裡最大的長度,即集合可以容納多少個元素,根據實際的容納量自動擴充的。永遠比count大。

1.7 字典集合(鍵值對集合的一種)

Dictionary<鍵的型別,值的型別> 名稱= new Dictionary<鍵的型別,值的型別>

例如:Dictionary<int,string> dis = new Dictionary<int,string>;

新增方式:

Dis.Add(1,”234234”);

Dis[4] = “dd”; 如果鍵已存在會覆蓋,沒有就會建立

字典長度:dis.Count

字典的遍歷:

for迴圈不能遍歷,哪怕字典鍵都是int也不能,因為可能存在空缺的鍵。

Foreach(KeyValuePair<int,string> item in dis){

Cw(“{0}{1}”,item.Key,item.Value);

}

Foreach(var fff in dis.Keys){

Cw(“{0}{1}”,fff,dis[fff]);

}

1.8 List泛型集合

List<T>   尖括號內T代表任意型別,是一個型別的佔位符

例如:List<int> list = new List<int>();

list.Add(1); list.Add(2); list.Add(3);

list.AddRange(new int[]{5,6,7,8,9});

list.AddRange(list);

長度:list.Count

轉成陣列:ToArray();

Int[] aa= list.ToArray();

陣列轉集合:

List<int> ll = aa.ToList();

1.9 自定義的泛型類

Class 類名<T>  where  T:struct  

T是任意型別,where是型別限定(根據需要寫,可以不寫)struct是限定為值型別,class是限定引用型別。

IComparable是限定只能是本介面的子類。

T只是一個代表,使用什麼字母都行,一般用T

Where T:Class,new();  限定為引用型別,並且使用了無參建構函式

舉例:

Public class Person<T> where {

Private int _age;

Private T _a;

Public T A{}

Public void sayhello(){

}

}

呼叫:

Person<int> p = new Person<int>();

1.9.1 自定義泛型類的方法

Public void Change<T>(ref T a ,ref T b){就是在方法名後加上泛型符號

T temp = a;

A= b;

B = temp;

}

Int a =5;int b=8;

呼叫:p.Change<int>(ref a,ref b);

普通類中可以有泛型方法,泛型類中也可以有普通方法

1.10 過載運算子

自己去定義運算子的意義,只能在類中過載,也只能對過載所在類的物件起作用。

關鍵字:operator

1、 必須用public修飾

2、 必須是類的靜態方法

3、 過載運算子==時,也必須過載!=運算子

4、 過載關係運算符>,>=時,也必須過載<,<=

5、 可以過載一元運算子:!++--,true,false

6、 可以過載的二元運算子:+-*/%&|^,<<,>>

7、 可以過載關係運算符:==,!=<,>,<=,>=

8、 一元運算子只能有一個引數,二元運算子有兩個引數

9、 在某種情況下,引數的型別必須與宣告的運算子的類或結構型別相同

舉例:

public class Person{

public int num1{get;set;}

public int num2{get;set;}

//public static Person operator +(引數列表,該引數必須與類的結構或者運算子的結構相同){//過載加好運算子,

}

public static Person operator +(Person op1,Person op2){

  Person p = new Person();

p.num1=op1.num1+op2.num1+op1.num2+op2.num2;

p.num2=op1.num1+op2.num1;

renturn p;

}

}

呼叫:

Person p1= new person();

P1.num1 = 3;

P1.num2 = 5;

Person p2 = new person();

P2.num1 = 4;

P2.num2 = 8;

Person p = p1+p2;//此時加號就是過載過的雙目運算子

Cw(“num1-{0},num2-{1}”,p.num1,p.num2);//p.num1=20;p.num2=7;

1.11 檔案類File

處理小型檔案的讀取和寫入,因為該類的方法會將檔案整個內容都讀取到記憶體中。該類屬於靜態類

使用需要匯入system.IO類庫

Flie.Create(路徑及檔名,大小限制); 建立檔案,返回值是fileStream

例如:File.Create(@“c:\cc\cc.txt”);

File.Delete(路徑及檔名);刪除檔案,

建議刪除建立之前先判斷有沒有,使用File.Exists();

File.Copy(複製的檔案及路徑,複製到的檔案和路徑名);貼上檔案

File.Copy(@“c:\cc\cc.txt”, @“c:\cc\bb.txt”);

剪下

File.Move(@“c:\cc\cc.txt”, @“c:\cc\bb.txt”);

上述方法的路徑一定要存在,系統不會自動建立資料夾路徑,並且,如果該檔案已存在會直接報錯

1.11.1 檔案編碼

儲存檔案:儲存資料的一種表現形式。

亂碼:儲存檔案和讀取檔案時編碼方式不一樣。

ASC碼錶 0-127  ASCII 0-255 GB2312  BIG5  Unicode(UTF-8, UTF-7)

一般使用UTF-8傳輸互動資料:3個位元組表示一個漢字

1.11.2 檔案類的操作

檔案內容讀取:

FileStream fs = File.Open(“路徑檔名”,開啟方式(FileMode.Open);

或者通過流的方式開啟檔案:FileStream fs = new FileStream(“路徑Filemode.Append);

開啟方式為FileMode.Open,後寫入的內容會覆蓋掉。Filemode.Append時不是覆蓋,而是追加。

Fs.Read(位元組陣列,第幾個開始,讀幾個);返回值是int,返回的內容是真是位元組的長度,例如:Fs.Read(建立一個空位元組陣列,0buffer.length);

fs.Length位元組流長度

str = File.ReadAllText(“路徑”);返回字串,讀取所有檔案內容為str

string[] strs = File.ReadAllLines(“路徑”);返回字串陣列,每一行為陣列的一個元素,讀取檔案內容的每一行為string陣列

File.ReadAllBytes(路徑及檔名);讀取檔案中所有行,然後關閉該檔案,返回值byte[]位元組陣列

Encoding.編碼格式.GetString(File.ReadAllBytes(路徑及檔名));byte[]陣列轉化成字串,返回值字串。

Encoding system.Text類庫的內容,需要先載入該名稱空間

檔案內容寫入:

FileStrem Fs = Flie.Create(路徑及檔名,大小限制);

Fs.Write(位元組數,第幾個開始寫,寫幾個);使用該方法第一步應該講對應字串內容轉化成位元組數,但轉換位元組數,需要先獲取編碼。

Byte[] buffer = System.Text.Encoding.編碼格式.GetBytes(str);f返回位元組陣列

寫完後,必須將fs.Close();關閉檔案流,負責會出現檔案佔用的問題。

此外還有File.WriteAllBytes方法

舉例說明:string str = “dsfasdfafdsaf”;

Byte[] bb = Encoding.Default.GetBytes(str);//default是預設編碼模式

File.WriteAllBytes(路徑及名稱,bb);該寫入操作會直接將原檔案內容覆蓋掉。

1.11.3 FileInfo

FileInfo 是密封類:能繼承別的類,別的類不能繼承密封類,只能坐子類。

FileInfo是非靜態類,用物件對檔案進行操作。

例如: FileInfo s = new FileInfo(路徑及檔名);

s.Create();

s.CopyTo();

s.MoveTo();

s.Delete();

1.11.4 對資料夾操作的靜態類Directory

Directory是靜態類

Directory.CreateDirectory(@“目錄結構\資料夾名”);建立資料夾,已有不再建立

Bool exits = Directory.Exists(@“路徑資料夾”);是否存在該資料夾