1.類與對象的關系
類是對一類事務的統稱,是抽象的,不能拿來直接使用,比如汽車,沒有具體指哪一輛汽車
對象是一個具體存在的,看的見,摸得着的,可以拿來直接使用,比如我家的那輛剛剛買的新汽車,就是具體的對象
對象是根據類這個模板創建出來的,類里面有哪些特性或者功能對象里面也有,多不得,少不得
2.new 一個對象做了哪些事情?
Person person = new Person();new是一個運算符
(1)在內存中開辟一塊合適大小的空間
(2)在這個空間里創建對象
(3)調用這個對象的構造函數
(4)返回這個空間的引用地址
3.訪問修飾符
類的訪問修飾符只有public和internal,內部類的訪問修飾符可以為private
4.屬性
屬性的本質是一個get和一個set方法,而set方法中定義了一個參數名稱為value,所以我們可以在set方法中訪問value
屬性就是對字段的封裝
屬性本身不存值,值是存在屬性封裝的對應的字段中
只要類中的字段要被外界訪問,就需要把這個字段封裝為屬性
5.構造函數
(1)構造函數訪問修飾符一般情況下是public,沒有返回值,方法的名稱與類名相同
(2)構造函數在創建這個對象的時候被自動調用,程序員無法手動調用
(3)構造函數有什么用?如果我們希望在創建這個類的對象的同時需要執行一些代碼,我們就可以將這些代碼寫到構造函數中
(4)this關鍵字代表當前對象,當前運行在內存中的那一個對象,this關鍵字可以調用其他的構造函數
(5)構造函數調用構造函數:
public Dog(int age,string name):this(age)
{
}
public Dog(int age)
{
}
調用的時候:Dog dog = new Dog(2,"旺財");程序會先調用Dog(int age)構造函數,然后在調用Dog(int age,string name)構造函數
(6)隱式構造函數:如果程序員沒有為類手動添加構造函數,C#編譯器在編譯的時候會自動添加一個無參數的構造函數
如果添加了構造函數,C#編譯器在編譯的時候則不會添加
6.常量和只讀變量
(1)const修飾的數據叫做常量,
常量一旦聲明常量的值就不能改變,因為C#編譯器在編譯的時候聲明常量的那句代碼不見了,在使用常量的地方就用常量的值替換了
比如
const string name = "小明";
Console.WriteLine(name);
編譯之后變為
Console.WriteLine("小明");所以不能賦值
readonly修飾的變量只讀變量
readonly string name = "小明";
public Person()
{
}
編譯后
readonly string name ;
public Person()
{
this.name = "小明";
}
const和readonly的區別:
const不能修改值,readonly只能在構造函數中修改值
const在編譯的時候就要確定值,readonly在運行時要確定值
7.枚舉
枚舉是一個值類型,每一個枚舉成員都對應了一個整型的數值,這個數值默認是從0開始遞增
枚舉和int類型轉換:int a = (int)Direction.South; int i = 2; Direction d = (Direction)i;
枚舉和string類型轉換:string str = "South"; Direction d = (Direction)Enum.Parse(typeof(Direction),str,true); //true表示忽略
大小寫
枚舉值所對應的數值默認是int類型的,可以在枚舉的名字后面加一個冒號來指定這個數值的類型,只能是整型的(byte,short。。。)
如:
enum Direction:byte
{
}
好處:限定變量的取值范圍,在編碼過程中不容易出錯
8.結構struct
(1)結構中可以定義字段、屬性、方法、構造函數,也可以通過new關鍵字來創建對象
(2)無參數的構造函數無論如何C#編譯器都會自動生成,所以我們不能顯示的聲明無參數的構造函數
(3)在構造函數中必須要為結構體的所有的字段賦值
(4)在構造函數中為屬性賦值,不認為是對字段賦值,因為屬性不一定是去操作字段
(5)結構是一個值類型,在傳遞結構變量的時候,會將結構對象里面的每一個字段復制一份,然后拷貝到新的對象中
(6)不能定義自動屬性,因為自動屬性會生成一個字段,而這個字段必須要求在構造函數中,而我們又不知道這個字段
(7)聲明結構體對象可以不new關鍵字,但是這個時候結構體對象的字段沒有初始值,因為沒有調用構造函數,而構造函數中必須為字段賦
值,所以通過new關鍵字創建的結構體對象的字段就有默認值。
(8)當我們要表示一個輕量級的對象的時候,就可以定位結構以提高速度。根據傳值的影響來選擇,希望傳引用就定義為類,希望傳拷貝就
定義為結構
9.垃圾回收
托管代碼:被CLR管理的代碼
非托管代碼:不被CLR管理的代碼
應用程序域:當。net應用程序在CLR中運行的時候,CLR會創建一個單獨的應用程序域,讓。net應用程序在應用程序域中運行
分配在棧空間的變量一旦執行完其所在的作用域(即"{ }"中),這個變量就會CLR立即回收
分配在堆里面的對象沒有任何對象引用的時候,這個對象就被標記為“垃圾對象”,等待垃圾回收期回收。
GC會定時的清理堆空間中的垃圾對象,GC清理垃圾對象的頻率程序員無法決定,由CLR自動控制
當一個對象被標記為“垃圾對象”的時候,這個對象不一定立即被回收
垃圾回收運行機制:
垃圾回收會根據應用程序的運行情況來使用合適的算法,其中一種算法如下:
CLR會預先開辟一塊空間,當創建對象的時候會放在第0代的內存中,當第0代的空間滿的時候,GC開始回收第0代,不被標記垃圾的對象會移
動到第1代內存中,然后第0代空間變為空,當再次創建對象的時候會存儲在第0代空間,一直這樣重復,第1代空間不滿的時候不會回收。當
第1代空間滿的時候,會垃圾回收第1代,然后把老的對象移動到第1代,新對象存儲在第0代。第1代到第2代是和第0代到第1代一樣,當三代
都滿的時候會報異常說內存溢出
GC.GetGeneration(p)獲取指定對象是屬於第幾代,總共有3代,從0開始,0,1,2
GC.Collect();立即讓垃圾回收器對所有的代進行垃圾回收
GC.Collect(0);表示對第0代回收GC.Collect(1);表示對第0代和第1代回收
Person p = new Person();
GC.GetGeneration(p);值為0
GC.Collect();
GC.GetGeneration(p);值為1
GC.Collect();
GC.GetGeneration(p);值為2
GC.Collect();
GC.GetGeneration(p);值為2
10.析構函數
析構函數不能有訪問修飾符,不能有參數,所有不能被繼承或重載,在對象被垃圾回收器回收的時候,析構函數被GC自動調用,當沒有垃圾
對象的時候不會被調用,
執行一些清理善后的操作
~Person()
{
}
11.靜態成員
(1)在這個類第一次被加載的時候,這個類下面所有的靜態成員會被加載,靜態成員是屬於類的,實例成員是屬於對象的
(2)靜態成員只能被創建一次,所以靜態成員只有一份,實例成員有多少個對象就創建多少次
(3)靜態成員被創建在靜態存儲區中,一旦創建直到程序退出才會被回收
(4)什么時候定義為靜態的?變量需要被共享的時候,方法需要被反復調用的時候
(5)靜態方法中不能直接調用實例成員,因為靜態方法被調用的時候,對象有可能沒有創建
(6)this/base關鍵字在靜態方法中不能使用,因為有可能對象不存在
(7)在實例方法中可以調用靜態成員,因為這個時候靜態成員肯定存在
靜態成員和實例成員區別:
(1)生命周期不同,靜態成員在程序退出時才會被回收,實例成員則在該對象被垃圾回收器回收時才會被回收
(2)存儲的位置不同,靜態成員存儲在靜態存儲區中,實例成員存儲在堆的對象里面
12.靜態類
(1)靜態類中只能聲明靜態成員
(2)靜態類中不能有實例構造函數
(3)靜態類中不能被實例化,因為沒有實例成員,實例化無意義
(4)靜態類不能被繼承,因為本質是一個抽象的密封類,所以不能被繼承也不能被實例化
(5)如果一個類下面的所有成員都需要被共享,那么就可以把這個類定義為靜態類
(6)不能聲明一個靜態類的變量,比如靜態類Person p;
靜態構造函數:非靜態類也可以有靜態構造函數
靜態類的成員第一次被訪問之前就會執行靜態構造函數
靜態構造函數只被執行一次