一. 交換兩個數據的值:
1. //創建一個臨時變量
//int temp;
//temp = num1;
////用num2的值覆蓋掉num1
//num1 = num2;
////將存儲在臨時變量中的nu1取出來賦值給num2
//num2 = temp;
2.不使用臨時變量:
num1 = num1 + num2; //11
num2 = num1 - num2; //11-6=5;
num1 = num1 - num2; //11-5=6
二:定義方法:
訪問修飾符 返回值類型 方法名稱(參數){方法體}
1. 訪問修飾符:public internal protected private
a) public :使用它來定義的成員可以在所有類里面使用(不同項目需要先引用)
b) private:私有的,只有在當前類中可以使用
c) protected:使用它來定義的成員只有在當前類或者當前類的子類中使用。
d) internal:在當前整個程序集中可以使用
2. 返回值類型
a) void:沒有返回值.(可以寫return(可以提前終止方法),但是不能return具體的值)
b) 非void,必須返回相應類型的值(任何類型都可以做為方法的返回值類型)
3. 方法名稱:
a) Pascal命名法,每一個單詞的首字母需要大寫
b) 不能使用關鍵字(int double bool string …..class namespace)
c) 不能包含_以外的特殊符號,不能以數字開頭 java(_ $)
4. 參數
a) 形參:只是一個參數的聲明,說明調用的時候需要傳遞過來的值(類型一致,個數一致,順序一致)---形參是實參的規范。Params 幫你創建一個數組,數組的長度由你傳遞過來的值個數決定 int[] arr=new int[0]
b) 形參是實參的規范 調用方法相當於實參為形參賦值(賦值的只是實參的值的副本 形參也是一個變量,需要獨立的存儲空間)
三:靜態與非靜態之間(成員)的調用方式:
1. 在單個類中:靜態不能直接調用非靜態成員(屬性,方法),只能通過實例化的對象調用。
2. 在單個類中:靜態可以直接調用靜態成員
3. 在單個類中:實例成員可以自由調用靜態成員(銀行 vip---非vip)
4. 在不同類中:實例成員通過類的對象調用,而靜態成員通過類名調用。const
5. 為什么靜態不能直接調用非靜態成員:靜態成員與類一起加載,在加載靜態成員的時候,非靜態成員還沒有生成。
四:C#Main方法的四種形式:
1. static void Main(string[] args)
2. static void Main()
3. static int Main(string[] args)
4. static int Main(s)
五:可變參數:params:它是一個數組類型的變量。會自動根據用戶傳遞的值生成一個數組(注意傳遞的值需要同一類型。)
1. 可以根據需要傳遞0 個或者多個參數。
2. 可變參數必須放在參數列表的最后
3. 如果沒有傳遞任何參數,需要做一個判斷,不然可能造成索引越界的錯誤。
4. 案例
private static int GetMax(string name,params int[] arr)
{
// int[] arr1 = new int[0];
if(arr.Length<=0)
{
return -1;
}
int max = arr[0]; //對於數組的比較不能直接將最大或者最小值賦值為0,應該賦值:max=arr[0]
for (int i = 0; i < arr.Length; i++)
{
if (max < arr[i])
{
max = arr[i];
}
}
return max;
}
六:c#中方法參數的默認值:
1. 參數可以賦默認值
2. 有默認值的參數必須在整個參數列表的最后
3. 在調用方法的時候可以選擇為參數賦值,如果賦值會覆蓋默認值,如果沒有就直接使用默認值。
4. 案例:
private static int GetMax(string name,string sex=“男”)
七:代碼規范:
1. 注釋:
a) // 單行注釋
b) /**/:多行注釋
c) ///文檔注釋:可以生成提示
2.變量命名:camel:第一個單詞首字母小寫,后面每一個單詞的首字母大寫
3.對於類和方法:每一個單詞首字母都要大寫。
4.代碼需要縮進與對齊。
記住:
1.在企事業里面可能這有這樣的建議:規定所有自定義變量都使用 _開頭
2.變量的名稱一般是名詞:說明這個變量有什么用
3.方法:一般是動詞,說明這個方法可以執行什么樣的操作
4.在定義變量的時候,長短不是關鍵,意義才是關鍵
八:數組:所有存儲結構中效率最高的。數組的長度一旦確定就不能再修改。因為它在內存中是一串連續的空間,它是通過下標直接計算出需要的值的位置,也說了說明了索引為什么不能越界
1. 如何定義:類型[] 名稱=new int[長度];
2. 數組里面只能存儲同一類型的值
3. 在c#中,[]只能寫在類型后面
4. 一般需要確定長度或者值,可以同時指定,但是長度與值的數量需要對應。
5. 因為數組長度固定,所以對數組的操作一般可以考慮使用for循環結構!
6. 數組元素的添加:
1. int[] arrScore = new int[5]{1,2,3,4,5};
2. arrScore[0]=1;//如果只為其中某一些下標對應的數組元素賦值那么其它的就會有默認值。
3. for (int i = 0; i < arrScore.Length; i++)
{
arrScore[i]=值;
}
7. 數組元素的修改:
ArrScore[i]=值;
8. 數組元素的遍歷:
for (int i = 0; i < arrScore.Length; i++)
{
if(arrScore[i]!=null) //對於引用類型象數組才有用(string)
{
}
Console.WriteLine(arrScore[i]);
}
9. 數組元素的刪除:
//1.先確定需要刪除的元素的位置(下標索引)--需要循環遍歷
for (int i = 0; i < arrScore.Length; i++)
{
if(arrScore[i]==num)
{
position = i;
}
}
Console.WriteLine("position:"+position);
//2.將這個值以后的所有值都往前面移動一位: arr[i] = arr[i + 1];//需要注意索引是否越界
for (int i = position; i < arrScore.Length-1;i++ )
{
arrScore[i] = arrScore[i + 1]; //將后面的元素值覆蓋前面元素值
}
//3.清空最后一個值:注意不同數組類型的默認值,這里因 整型數組的默認是0.所以這里只是清空到0
arrScore[arrScore.Length - 1] = 0;
10. 練習:創建長度動態可以變化的數組—為集合做准備:
int[] arr=new int[2];
/// <summary>
/// 數組中已經存儲的元素的個數
/// </summary>
int count=0;
#region 往數組中添加元素 +void Add(int num)
/// <summary>
/// 往數組中添加元素,約定:數組中的元素不能是0
/// </summary>
public void Add(int num)
{
if(count==arr.Length) //當數組中存儲的元素的個數剛好等於數組的長度的時候,數組就需要擴容
{
int[] newArr=new int[arr.Length*2]; //數組的長度不可能動態變化,所以只能創建一個新的數組,長度是原始數組的兩倍
//將原始數組的值移動到新數組中
arr.CopyTo(newArr, 0);
//重新指定數組的地址引用
arr = newArr;
}
arr[count] = num; //第一次的時候count=0
count++; //添加一個元素,個數值增1
}
#endregion
九:二維數組和交錯數組
1. 二維數組
a) 定義:int[,] arr=new int[3,4];//必須指定二個維度的值
b) 遍歷:通過getLength取得維度的長度值:代碼如下:
for (int i = 0; i < twoDArr.GetLength(0);i++ )
{
for (int j = 0; j < twoDArr.GetLength(1);j++ )
{
Console.Write(twoDArr[i,j]+" ");
}
Console.WriteLine();
}
2. 交錯數組
a) 交錯數組的本質就是一個一維數組,只不過這個數組里面的每一個元素值又不一個數組
b) 交錯數組的元素需要先實例化,因為數組是一個引用類型的變量,需要先實例化再使用,如果沒有實例化會出現 “未將對象引用設置到對象的實例”
c) 因為交錯數組的每一個元素類型是數組,所以遍歷的時候就可以按遍歷一維數組的方式一考慮,代碼如下:
int[][] arr=new int[2][];
//數組的每個元素又是一個數組對象,所以需要先實例化數組對象
arr[0] = new int[] { 1, 2, 3 };
arr[1] = new int[] { 1, 2, 3,4,5,6,7,8,9 };
for (int i = 0; i < arr.Length;i++ )
{
for (int j = 0; j < arr[i].Length;j++ )
{
Console.Write(arr[i][j]+" ");
}
Console.WriteLine();
}
十:return:
1. 可以返回一個變量---當方法有返回值類型的時候
2. 還可以中止當前方法
3. 如果在異常處理結構里面,不管是否之前運行到return,finally的代碼都會被執行。
十一:變量的作用域:
1. 全局變量(成員變量):類的屬性:public private
2. 局部變量:在方法體內定義的變量---作用域只是在方法體內,出了方法體就不能再使用,如果一定需要使用,有三個方法:
a) 可以做為參數傳遞
b) 還可以做為返回值
c) 還可以做成類的成員變量---靜態成員變量不是很安全
十二:方法重載:系統會根據調用方法傳遞的實參來自動匹配擁有相應形參的方法。
1. 方法名稱一致,但是方法的參數不一致(參數的類型不一致,參數的數量不一致),只要滿足其中一個就構成重載的條件(如果兩個都滿足那一定構成重載的條件)--與方法的返回值無關,也與方法的訪問類型無關。
2. 這里的方法重載是指同一個類中方法重名,參數不一致的情況。
3. 作用:同一個名稱,多種響應結果(與你的參數有關系),解決了命名煩惱。
十三:普通的值傳遞和ref傳遞參數:
1, 普通的值做為參數傳遞的時候,傳遞是其實是值的副本,對副本的操作不影響到原始值
2, 所謂值的副本是指存儲在棧空間里面的內容的副本。對於值類型的變量而言,棧空間里面存儲的就是值本身,但是是對於引用類型的變量而言,棧里面存儲的是引用地址。
3, 如果使用了ref/out傳遞參數,那么傳遞是存儲了值類型數據的棧空間地址,會造成原始值和方法形參指向同一個地址空間,在方法里面進行的修改會影響到原始值。
4, Ref側重於輸入,out側重於修改。如果使用out傳遞參數,那么:1.在方法里面必須對傳入的參數進行值的修改。2.out傳入參數可以不為實參賦值
十四:面向對象:一種分析問題的方式,當你需要完成一個功能,就去找能夠實現這個功能的對象。對象來自於類。而類來自於現實生活中需要模擬的對象
1. 封裝:屬性封裝,方法 ,類,程序集都是封裝
2. 繼承
3. 多態
十五:this:當前創建的對象是那一個,this就代表當前對象
十六:類的對象的關系:
1. 類是用來描述事物的,是模型,是一個概念,它的成員:屬性(描述的對象的特征) 方法(描述的對象的行為)
2. 對象是類的實例,是具體的存在。
3. 類的成員有兩種:字段/屬性,行為/方法:
十七:構造函數:它就是構建類的對象用的。一個特殊的方法:返回值,重載,傳遞參數
1. 沒有返回值,名稱和類名一致,任何成員(除了構造函數)名稱都不能和類名一致
2. 每一個類都會有一個默認的無參的構造函數。
3. 構造函數不能像普通方法一樣顯示調用,只能創建對象的時候調用,以及子類base(當前類也可以this)顯式的調用父類的構造函數
4. 如果人為添加了帶參的構造函數,那么系統默認生成的無參構造函數會自動消失。所以一般我們應該養成一個習慣:創建好一個類,立刻為其添加無參的構造函數。
5. 構造函數也可以重載。 方法名稱一致, 參數不一致(類型不一致,個數不一致)
6. 使用this調用當前類的構造函數:
class Student:Person //默認是當前程序集中可以使用而已
{
//任何一個成員的名稱都不能與類名一致,除了構造函數
private void Student()
{
}
/// <summary>
/// 創建子類對象,默認會調用父類的無參的構造函數,除非你指定調用父類的那一個帶參的構造函數
/// </summary>
public Student(string name,string sex,int age)
{
this.Name = name;
this.Gender = sex;
this.Age = age;
}
public Student(string name, string sex, int age,string no):this(name,sex,age)
{
this.StuNo = no;
}
7. 使用base調用父類構造函數:
class Student:Person //默認是當前程序集中可以使用而已
{
public Student(string name,string sex,int age):base(name,sex,age)
{
}
}
十八:屬性:對象的特征:
1. 屬性的作用:封裝字段,提供一種過濾的方式 get是指獲取(讀取),set(賦值)
2. 屬性的本質:兩個方法 Set() Get()
3. 屬性封裝的實現:value相當於一個隱藏的參數,它就是用戶賦的值。
4. 如果過濾:做驗證:
set
{
if (value > 0 && value <= 100)
{
age = value;
}
else
{
age = 18;
}
}
5.自動屬性:public int Age{get;set;}
十九:繼承
1. 可以將多個類的公共的屬性和行為提取到一個公共類中,這個公共類就可以稱為父類。
2. 父類只能包含子類共有的成員,不是所有子類都擁有的成員不能在父類中創建。
3. 子類繼承父類,必須能夠實現父類中所規范的所有成員,如果不能實現所有成員繼承關系就不能成立。
4. 使用 : 實現繼承。
5. 如果子類擁有與父類重名的屬性和方法的時候,子類的屬性和方法會將父類的覆蓋掉。如果需要顯示調用父類的成員,則需要使用base.不然會默認調用this.
6. 創建一個子類對象,默認先會調用父類的無參的構造函數。如果父類沒有無參的構造函數,會報錯。
7. 創建子類對象的時候,也可以指定調用父類的帶參的構造函數。Base
8. 子類會繼承父類的所有成員,但是只能使用公共的,而私有成員不能使用。
9. 繼承有三大特性:
a) 單根性:一個類只能繼承自另外一個類
b) 傳遞性:一個類是另外一個類的子類,也可能同時是另外一個子類的父類
c) 單向性:不能循環依賴
二十:多態的實現:同一種操作,多種不同的相應。
1. 聲明父類變量,實例化子類對象 Person per=new Student();
2. 父類創建虛方法,子類做重寫。---子類重寫父類的方法
3. 虛方法提供了默認的實現,子類可以不重寫,如果子類沒有重寫,那么就默認調用父提供的方法實現。如果子類重寫了,系統會自動判斷子類類型,調用子類的重寫方法 -----這就是多態
4. 多態的核心在於:子類可以替換父類,原因:
a) 子類擁有父類所規范的所有屬性和方法
b) 子類還可以擁有自己特定的屬性和方法
c) 父類對象可以完成的功能子類對象都可以完成
d) 所以,子類可以替換父類。如Person per=new Student();
e) Per本質是一個子類對象,但是編譯器不知道,所以per只能調用父類里面規范的成員。如果做強制轉換,則可以調用到子類成員。
5. 如果需要系統自動判斷類型,達到多態的目的需要做以下事情:
a) 實現繼承---- 子類是父類
b) 父類中聲明虛方法(抽象方法),子類做重寫(override)
c) 聲明父類變量,實例化子類對象 / 父類做為參數,傳入子類對象。
6. 多態實現了避免反復的判斷才能達到的效果,這也是多態的好處。方便以后的代碼功能的擴展
7. 抽象方法:abstract:只是方法的聲明,沒有方法體,不能包含{},但是必須包含 ;
8. 抽象方法的特點 :
a) 只有聲明
b) 它必須在抽象類里面(抽象類里面不僅僅只包含抽象方法)
c) 所有子類必須重寫父類的抽象方法,除非子類它也是抽象的,抽象類里面可以包含未實現的抽象方法 。
d) 抽象方法更多是一種規范,它規范了子類的行為。---接口
e) 抽象類不能實例化。
9、多態的使用方式:
1.聲明父類變量,實例化子類對象 ---創建父類類型集合
2.以父類做為方法的返回值,返回子類對象---簡單工廠:用戶需要頻繁的得到不同的單個子類對象的時候
3.以父類類型做為參數,傳入子類對象
10.如果父子類的方法參數不一樣,那它是重載而不是重寫。
11.重寫要求方法的簽名完全一致:訪問類型一樣,返回值類型一樣,方法名稱一樣,方法的參數一樣,只是方法體的實現過程不一樣
二十一:簡單工廠:制作產品:根據用戶的需要,每一次制作出一個產品
public static Operator CreateOperator(string type)
{
Operator opt = null;
if (type == "+")
{
opt = new OpAdd();
}
if (type == "-")
{
opt = new SubStract();
}
if (type == "*")
{
opt = new Multi();
}
if (type == "/")
{
opt = new Div();
}
return opt;
}
二十二:is/as
1. is用來判斷引用類型變量的變量是否是某一種類型
2. as:來做強制轉換,一般()轉換,如果不成功,就會報異常,as如果轉換不成功會返回NULL,以后,如果不想拋出異常,可以使用as
二十三:軟件設計中的幾個原則:
1. 封裝變化點
2. 開放封閉原則(對修改封閉,對擴展開放)---添加單獨的功能—添加單獨的方法; 添加單獨的角色---添加單獨的類
3. 高內聚,低藕合
二十四:接口:
1. 接口本質就是一個抽象類,在接口里面就是聲明一系列的屬性,方法,索引器和事件。從反編譯工具可以看到接口是抽象類---抽象的不能實例化,只能被實現;接口是一個類,說明它也是一種數據類型,可以通過接口創建出接口對象(所謂的接口對象其實是實現該接口的類的對象)
2. 創建一個接口對象,其實就是創建一個 實現了這個接口的類 的對象
3. 如果某個類沒有實現某個接口,那么這個這個類的對象不能強制轉換為接口類型。
4. 接口不要求實現接口的類有某種關聯(只需要有共同的行為),也就是說不要求他們要父子繼承關系,方便了用戶的拓展。 父類---虛方法/抽象方法---子類重寫---多態
5. 在公司里面,接口更多的認為是一種規范。
6. 使用接口的方式:
a) 聲明接口類型的變量,存入 實現了接口的類的 對象
b) 以接口類型做為參數,傳入 實現了接口的類的 對象
7. 顯示調用接口:顯示實現接口的方法需要接口類型的對象才能調用。因類它默認是私有的,而且還不能人為修改為public
a) 如果聲明的類型就是接口類型,那么可直接調用
b) 如果聲明的類型是實現了接口的類的類型,那么就需要做強制轉換。
8. 接口解決了通過繼承實現多態的三個問題:
a) 通過繼承實現多態只能是單繼承,但是接口可以多實現
b) 通過繼承實現多態的類必能夠提取出共同的父類,也就說明這些類之間需要有共同的特征和行為。但是接口只需要它們有共同的行為。
c) 通過實現了繼承的類做為參數傳遞,會傳遞類的對象的所有屬性和方法,但是通過接口做為參數,只能調用到接口中聲明的方法和屬性。---更加安全
二十五:結構
1, 結構是值 類繼承自ValueType型
2, 它的使用方式和類很相似,但是也有一些區別:
a) 結構中不能為字段賦值
b) 結構不能包含顯式的無參數構造函數
c) 如果通過構造函數為結構成員賦值,只能賦值給字段。
d) 如果不使用new來創建結構,那么就必須為結構中的字段賦值。
e) 結構是一個值類型,所以在做為參數傳遞的時候傳遞是值的副本,與引用類型不一致
f) 值類型做參數傳遞的時候會開辟新的空間來存儲值,同時在同引用類型做轉換的時候 需要 裝箱和拆箱操作,消耗系統資源。
二十六:析構函數:
1. 每個類只能有一個,不能顯示調用
2. 不能有訪問修飾符,是系統自動調用的
3. ~Student()
{
Console.WriteLine("我調用了析構函數");
}