1.繼承
(1)創建子類對象的時候,在子類對象中會為子類對象的字段開辟空間,也會為父類的所有字段開辟空間,只不過父類私有的成員訪問不到
(2)子類從父類繼承父類所有的非私有成員,但是父類的所有字段也會創建,只不過父類私有的成員訪問不到
(3)base關鍵字可以調用父類的非私有成員
(4)子類的訪問級別不能比父類高,原因是訪問子類的同時也訪問了父類,如果子類的訪問級別不能比父類高,就矛盾了
(5)創建子類的時候,會先調用子類的構造函數,然后調用父類的構造函數,然后執行父類的構造函數,最后再執行子類的構造函數
(6)子類的構造函數后面默認加了一個:base()通過這個調用父類的無參構造函數,如果父類沒有無參數的構造函數,將會報錯,因為子
類的構造函數默認會調用父類的無參數的構造函數
(7)使用base關鍵字可以顯示的指定子類構造函數調用父類的構造函數
(8)繼承的特征:
單根性:類只能有一個父類
傳遞性:子類繼承父類所有的非私有成員
(9)父類與子類存在同名成員的時候,如果創建一個子類對象,調用這個子類對象的同名方法會調用子類的
(10)new關鍵字的第2作用隱藏父類的同名成員
2.里氏替換原則LSP
子類可以替換父類的位置,並且程序的功能不受影響
Person p = new Student();
p.SayHi();//這個是調用Person的SayHi()
如果一個父類變量指向的是子類對象,將這個父類對象轉換為子類對象不會報錯
Person p = new Student();
Student s = (Student)p;這種類型轉換不會報錯
如果一個父類變量指向的就是一個父類對象,將這個父類對象轉換為子類對象會報錯
Person p = new Person();
Student s = (Student)p;這種類型轉換會報錯
3.虛方法 virtual關鍵字
如果子類重寫了父類的虛方法,那么通過父類變量來調用這個方法的時候會調用子類的,如果沒有,則會調用父類的
4.多態
同一種行為,對於不同的事物,有不同的表現形式
多態的表現形式之一:將父類類型作為方法的參數,屏蔽多個子類的不同,將多個子類當成父類來統一處理
多態的表現形式之二:將父類類型作為方法的返回值
5.抽象類、抽象方法
(1)抽象方法用abstract關鍵字修飾,抽象方法不能有方法體,抽象方法必須在抽象類中
(2)抽象類不能實例化,因為有抽象成員,而抽象成員沒有方法體的
(3)如果子類繼承抽象類,子類必須重寫父類的抽象方法
(4)抽象類中可以擁有非抽象成員,為了繼承給子類
(5)當子類必須重寫父類的方法或者父類沒有必要實例化就用抽象類
6.Equals
object類里面的equals方法是比較兩個對象的引用地址,如果引用地址是一樣的返回true
string str1 = "abc";
string str2 = "abc";
str1.Equals(str2);//返回True,這個Equals方法是string類的,string類的Equals方法是比較兩個字符串的內容是否相同
int a = 1;
int b = 1;
a.Equals(b);//返回True
值類型Equals方法比較的是兩個結構對象里字段的值(這個時候不存在重寫,只是值類型自己新增的一個Equals方法)
所以:
引用類型的Equals方法默認比較的是兩個對象的引用地址
string類型,值類型的Equals方法比較的是兩個結構對象里字段的值
7.接口
(1)接口表示具有某種能力
(2)接口的本質是一個特殊的抽象類
(3)接口中的成員默認就是抽象的
(4)接口中只能定義方法、屬性、事件、索引器
(5)接口中抽象成員不能有訪問修飾符,默認就是public
(6)接口就是一個純粹的為了規范實現類的
(7)string Name{get;set;}這個在接口中不是一個自動屬性,是一個普通的屬性,只不過get set方法沒有實現
(8)什么時候使用抽象類:可以找到父類,並且希望通過父類繼承給子類一些成員
什么時候使用接口:多個類具有相同的方法,但是卻找不出父類
(9)顯示實現接口:是為了解決方法名沖突的問題,顯示實現的接口的方法是私有的,所以不能通過對象的變量來調用
(10)顯示實現接口:這個接口的實現方法只能通過接口變量來調用
(11)要避免定義多功能接口,以免造成接口污染
8.裝箱拆箱
裝箱:值類型轉化為引用類型int i = 12; object obj = i;
拆箱:引用類型轉換為值類型 int j = (int)obj;
裝箱和拆箱是比較消耗性能的,要盡量去避免裝箱和拆箱操作
(1).裝箱、拆箱必須是: 值類型→引用類型 或 引用類型→值類型。
int類型為什么能裝箱到object類型,但不能裝箱到string類型或Person類型,因為object類型是int類型的父類。
(2).拆箱時,必須用裝箱時的類型來拆箱
裝箱時如果是int,拆箱必須用int,不能用double
(3).方法重載時,如果具有該類型的重載,那么就不叫拆箱或裝箱。
int n=10; Console.WriteLine(n);//沒有發生裝箱,因為方法重載。Console.WriteLine(int n);方法重載
//這個不叫裝箱
int x=100;
string s=x.ToString();
(4).將值類型轉換為引用類型(int→object)的時候,性能影響很大。一倍。
裝箱:將值類型轉換為引用類型。
拆箱:將引用類型轉換為值類型。
(5).接口與值類型之間的裝箱和拆箱
int n = 10;
IComparable compar = n; //裝箱。
(6). string s1 = "a";
string s2 = "b";
int n3 = 10;
double d4 = 99.9;
string result = string.Concat(s1, s2, n3, d4);//string.Concat(string str0,string str1,string str2,string str3)
//Q1:有沒有發生裝箱? 有!
//Q2:如果有,發生了幾次? 2
Console.WriteLine(result);
int n = 10;
string s1 = n.ToString();//沒有發生裝箱,因為Int32重寫了從父類(ValueType)繼承下來的ToString()方法,現在這個ToString()方法已經是Int32自己的了。
string s2 = n.GetType().ToString();//這里發生了裝箱,在調用GetType()方法時發生了裝箱,因為GetType()是從Object繼承過來的,要調用這個方法必須通過object對象調用。所以要先裝箱。
Console.WriteLine(s1 + "\t\t\t" + s2);
9.字符串
(1)字符串是特殊的引用類型
(2)字符串我們可以看做是一個字符數組string str = "abcd";char c = str[0];
(3)字符串對象一旦創建,這個對象就不能被修改
(4)在創建一個字符串對象的時候,會先去字符串拘留池中尋找是否有相同字符串內容的對象,如果有就直接讓變量指向這個對象,如果沒
有再創建新的對象
比如:string s1 = "a"; string s2 = "b"; s1 = "b"; s1的引用地址和s2的引用地址是相同的,都指向字符串拘留池中的“b”,不會再創
建一個“b”
(5)字符串對象一旦創建,不會被GC回收,因為微軟就認為字符串是常用的
(6)字符串常用的方法、屬性:
String s = new String(new char[]{'a','b'});//構造函數只能傳遞字符數組
int i = s.Length
string s = string.Empty代表一個空的字符串 "",不是指的null string.Empty等於"",推薦使用string.Empty;為了防止不會寫錯
int i = string.Compare(s1,s2);比較兩個字符串的大小,返回-1,0,1
string s = string.Concat(s1,s2)連接字符串並組成一個新的字符串
bool b = s.Contains("ab");判斷字符串里面是否包含指定的字符串
b = s.EndWith("b");判斷字符串是否以指定的字符串結尾
b = s.StartsWith("a");判斷字符串是否以指定的字符串開始
int i = s.IndexOf('a');查找指定的字符或者字符串在字符串中的索引,如果沒有返回-1
int i = s.LastIndexOf('!');從字符串的結尾往前面查,第一次字符串出現的索引
string s = s.Insert(1,"c");在字符串的指定位置插入字符串
char[] c = s.ToCharArray()將字符串轉換為字符數組
還有好多方法就不寫了
(7)StringBuilder
StringBuilder這個類的對象是可變的,當改變這個對象的字符串時,不會新開辟空間,而是直接改變。
10.Stopwatch watch = new Stopwatch();//計時器
watch.Start();
watch.Stop();
watch.ElapsedMilliseconds毫秒數