用程式來抽象現實世界,(萬物皆物件)來程式設計實現功能。
三大特性:封裝、繼承、多型。
宣告位置:namespace
中
樣式:class 類名{}
命名:帕斯卡命名法(首字母大寫)
範例化物件:根據類來新建一個物件。Person p=new Person();
enum E_SexType
{
Man,
Woman
}
struct Position{}//位置結構體
class Pet{}//寵物類
//類中的成員變數
class Person
{
public string name="TonyChang";//區別於結構體--可以預設賦初始值
public int age=21;
public E_SexType sex;
public Person bestFriend;//區別於結構體---類中可以有同類的成員型別(本質是因為類屬於參照型別,但不可以範例化,防止反覆new,陷入死迴圈)
public Position pos;
public Pet pet;
}
成員型別的預設值:
值型別的:數位的為0,bool
型別的false
參照型別:null
檢視(int型別)預設值:default(int)
補充:class屬於參照型別,其中的值型別也放置在堆中。
成員方法只有在範例化之後才可以使用呼叫。具體的一個物件的行為(方法),必須具體的物件呼叫。
//成員方法
class Person
{
public string name;
public int age;
public void Speak()
{
Console.WriteLine("你好!");
}
}
//成員方法的使用
Person p=new Person;
p.Speak();
預設有一個無參建構函式,而類中可以允許自己宣告無參建構函式,而結構體不行。
一旦有自定義的建構函式,預設的無參建構函式則失效!
建構函式:
class Person
{
public string name;
public int age;
//建構函式
public Person()
{
name="TonyChang";
age=21;
}
//此時先呼叫age引數的建構函式 然後再呼叫兩個引數的建構函式
public Person(string name,int age):this(age)
{
this.name=name;
this.age=age;
}
public Person(string name)
{
this.name=name;
}
public Person(int age)
{
this.age=age;
}
}
特殊的建構函式,在呼叫該函數之前先呼叫this的無參建構函式。
public Person(int age):this()
{
this.age=age;
}
解構函式:
由於C#中有自動的垃圾回收機制,一般不使用解構函式。
解構函式是當垃圾真正被回收時候才會呼叫。
~Person(){}
//解構函式
用於保護成員變數,為成員屬性的獲取和賦值新增邏輯處理。
//成員屬性 帕斯卡命名法
class Person
{
private string name;
public string Name
{
get{
return name;
}
set{
name=value;
}
}
private int age;
public int Age
{
//不可以獲得年齡(或者刪除set設定則可表明也無法獲取age)
private get=>age;
//可以設定年齡
set
{
age=value;
}
}
//額外:
//自動成員屬性 (對於沒有特殊需要的成員)
public float Height
{
get;
set;
}
}
可以讓物件像陣列一樣通過索引來存取其中的元素。
注意:結構體中也支援索引器。
//索引器
class Person
{
private string name;
private int age;
private Person[] friends;
private int[,] arry;
//索引器
public Person this[int index]
{
get
{
return friends[index];
}
set
{
//此處可以寫一些控制邏輯
friends[index]=value;
}
}
//索引器的過載
public int this[int i,int j]
{
get
{
return array[i,j];
}
set
{
array[i,j]=value;
}
}
}
//使用
Person p=new Person();
p[0]=new Person();//可以像陣列一樣進行存取
static
修飾的成員變數/方法為靜態成員。
靜態成員歸屬為類,即不用初始化就可以使用的類的成員。
靜態成員函數中不可以使用非靜態成員,非靜態成員函數中可以使用靜態成員函數。
本質:在程式執行開始時,檢查到靜態成員,會再特定的區域為其開闢記憶體空間來儲存。所以說靜態成員與程式共生死。因為生命週期不同,所以靜態成員函數中不可以使用非靜態成員。
使用:全域性性,穩定不變的常數。例如固定的數值 Π,重力加速度g等包括固定的計算方法,可以供全域性成員來存取使用。但是靜態過多會佔用記憶體,引發GC。
相同點:都可以通過類名點來使用
不同點:
const
必須初始化,不能修改,而static可以const
只能修飾變數,而static可以修飾很多const
一定是寫在存取修飾符的後面,static則無此要求用 static修飾的類為靜態類,往往來作為工具類。例如System中的Console類。只能包含靜態成員,不能範例化。
靜態建構函式 :在靜態建構函式中初始化靜態成員變數。
//靜態建構函式
static class Test
{
public static int testInt=100;
public static float testFloat=20.5f;
static Test()
{
//靜態建構函式
Console.WriteLine("自動呼叫了!");
}
}
class NormalTest
{
public static int i=5;
//首次使用靜態成員時候 自動呼叫一次
//靜態成員函數
static NormalTest()
{
Console.WriteLine("靜態建構函式");
}
public NormalTest()
{
Console.WriteLine("非靜態成員函數");
}
}
拓展方法為現有的非靜態變數型別新增新方法。
作用:
特點:
//拓展方法
static class expendTool
{
//為int新增拓展方法
public static void SpeakValue(this int value)
{
Console.WriteLine("這是int的拓展方法,int的數值為{0}",value);
}
//為string拓展方法
public static void SpeakStringInfo(this string str,string name,string info)
{
Console.WriteLine("這是string的拓展方法,string的數值為{0},該拓展方法由{1}編寫,拓展內容為{2}",str,name,info);
}
}
class Program
{
static void Main(string[] args)
{
int i = 5;
i.SpeakValue();
string ss = "原始字串";
ss.SpeakStringInfo("TonyChang", "附加字串");
}
}
注意:如果拓展方法名稱與自身現有的方法名稱相同,則只會呼叫自身的方法,不會呼叫拓展的方法。
關鍵字 operator
特點:1. 一定是一個公共的靜態成員方法
作用:可以使自定義的資料型別來完成後相同意義的運算。
注意:
//運運算元過載
class Point
{
public int x;
public int y;
public Point(int x,int y)
{
this.x=x;
this.y=y;
}
//過載+運運算元
//參數列中必須要有自己的類別出現
public static Point operator +(Point p1,Point p2)
{
Point sum=new Point();
sum.x=p1.x+p2.x;
sum.y=p1.y+p2.y;
return sum;
}
}
class Program
{
static void Main(string[] args)
{
Point p1=new Point(1,1);
Point p2=new Point(2,2);
Point p3=P1+p2;
Console.WriteLine(p3.x);
}
}
補充:大部運運算元可以過載,邏輯運運算元中只可以允許過載 邏輯非!
不能過載的運運算元有:
&& || 索引符[] 強制轉換符號() 特殊運運算元 點. 三目運運算元?:
//內部類
class Person
{
public class Body
{
class Arm
{
}
}
}
class Program
{
static void Main(string[] args)
{
Person.Body body=new Person.Body();
}
}
//分佈類
//分佈類可以分佈在不同的指令碼檔案中
//分佈類的存取修飾符要一致
partial class Student
{
public string name;
public bool sex;
partial void Speak();
}
partial class Student
{
public int age;
public string stuId;
partial void Speak()
{
Console.WriteLine("分佈方法的具體實現");
}
}
垃圾回收,英文簡稱GC(Garbage Collector)
垃圾回收過程:遍歷堆(Heap)上的動態分配的所有物件
通過識別它們是否被參照來確定其是否是垃圾。垃圾是指沒有參照所指引的物件、變數,需要被回收釋放掉佔用的記憶體空間。
垃圾回收演演算法:
參照計數、標記清除、標記整理、複製集合。
注意:垃圾回收只回收heap堆上的 棧中的記憶體由系統管理
回收機制: 三代記憶體
0代記憶體 1代記憶體 2代記憶體
每一代記憶體滿掉之後便會清理垃圾
高代連鎖:1代清理會連帶0代清理,2代清理連帶0代和1代
清理完垃圾之後,非垃圾內容搬遷到下一代中(0代將非垃圾轉移到1代記憶體,
1代記憶體將非垃圾轉移到2代記憶體)所以2代記憶體儲存的較為老的物件範例,還包括大的物件
一般是85kb以上的物件
0代1代的讀取速度要高於1代,分配記憶體位置優先0代>1代>2代
手動GC:
GC.Collect();
一般在場景載入時候進行GC。
繼承者(子類)繼承父類別(基礎類別、超類)的特性,同時也可以有自己獨特的方法性質。
只能單繼承。子類只能由一個父類別。
繼承特性:單根性、傳遞性。
//繼承
//老師類
class Teacher
{
//姓名
public string name;
//職工號
protected int number;
//介紹名字
public void SpeakName()
{
number = 10;
Console.WriteLine(name);
}
}
//教學老師繼承老師類
class TeachingTeacher : Teacher
{
//科目
public string subject;
//介紹科目
public void SpeakSubject()
{
number = 11;
Console.WriteLine(subject + "老師");
}
}
//語文老師繼承教學老師類
class ChineseTeacher:TeachingTeacher
{
public void Skill()
{
Console.WriteLine("一行白鷺上青天");
}
}
class Program
{
static void Main(string[] args)
{
TeachingTeacher tt = new TeachingTeacher();
tt.name = "汪老師";
//tt.number = 1;
tt.SpeakName();
tt.subject = "Unity";
tt.SpeakSubject();
ChineseTeacher ct = new ChineseTeacher();
ct.name = "張老師";
//ct.number = 2;
ct.subject = "語文";
ct.SpeakName();
ct.SpeakSubject();
ct.Skill();
}
}
父類別容器裝在子類物件。(任何父類別出現的地方,子類都可以替代)
class GameObject
{
}
class Player:GameObject
{
public void PlayerAtk()
{
Console.WriteLine("玩家攻擊");
}
}
class Monster:GameObject
{
public void MonsterAtk()
{
Console.WriteLine("怪物攻擊");
}
}
class Boss:GameObject
{
public void BossAtk()
{
Console.WriteLine("Boss攻擊");
}
}
class Program
{
static void Main(string[] args)
{
//里氏替換原則
Gameobjet player=new Player();
Gameobjet monster=new Monster();
Gameobjet boss=new Boss();
//is 和 as
if(player is Player)
{
(player as Player).PlayerAtk();
}
}
}
is是判斷一個物件是否為指定型別物件,返回值為true則為真,不是則為false
as用來將一個物件轉換為指定型別物件,返回值為指定型別物件,若轉換失敗則返回null
子類建構函式呼叫之前,先執行父類別的建構函式。(爺爺-->父親-->子類)
所以要保證父類別的建構函式(尤其為無參建構函式)
//繼承中的建構函式
class Father
{
//父類別的無參建構函式很重要!
public Father()
{
}
public Father(int i)
{
Console.WriteLine("Father的有參構造");
}
}
class Son:Father
{
public Son(int i):base(i)
{
//建構函式
}
}
object 是所有型別的基礎類別,
作用:
裝箱:
用object存值型別。本該在棧中數值轉移到堆上
拆箱
將object轉換為值型別,將堆上的值型別轉移到棧上(配合 is和as 使用)
優點:統一物件型別(里氏替換原則),方便對不同型別物件數值的管理
缺點:消耗效能,
//裝箱拆箱
int i=5;
object obj=i;//裝箱
i=(int)obj;//拆箱
使用sealed關鍵字修飾的類,不可以被派生。(結紮了!)
V: virtual(虛擬函式)
O: override(重寫)
B: base(父類別)
讓繼承同一父類別的子類們在執行相同方法有不同的表現與狀態。
就是說,繼承是一脈相承父類別的品質,而多型是由自己的個性,儘管做的和父輩的事情相同。
解決的問題:
class Father
{
public void SpeakName()
{
Console.WriteLine("Father的方法");
}
}
class Son:Father
{
public new void SpeakName()
{
Console.WriteLine("Son的方法");
}
}
class Program
{
static void Main(string[] args)
{
#region 解決的問題
Father f = new Son();
f.SpeakName();//呼叫的是父親的方法
(f as Son).SpeakName();//呼叫的是兒子的方法
#endregion
}
}
使用多型來保證(繼承類)一個類方法的獨立性
class GameObject
{
public string name;
public GameObject(string name)
{
this.name = name;
}
//虛擬函式 可以被子類重寫
public virtual void Atk()
{
Console.WriteLine("遊戲物件進行攻擊");
}
}
class Player:GameObject
{
public Player(string name):base(name)
{
}
//重寫虛擬函式
public override void Atk()
{
//base的作用
//代表父類別 可以通過base來保留父類別的行為
base.Atk();
Console.WriteLine("玩家物件進行攻擊");
}
}
抽象類不可以被範例化
abstract class Thing{
public string name;
}
抽象方法:沒有方法體的純虛方法,繼承的子類必須實現純虛方法。(子類必須重寫該方法,子類的子類不必強制實行,但也可以繼續重寫。)
抽象方法與virtual(虛擬函式)方法區別:
abstract class Fruits
{
public string name;
//抽象方法 是一定不能有函數體的
public abstract void Bad();
public virtual void Test()
{
//可以選擇是否寫邏輯
}
}
class Apple : Fruits
{
public override void Bad()
{
}
//虛方法是可以由我們子類選擇性來實現的
//抽象方法必須要實現
}
概念:介面是行為的抽象規範
關鍵字:interface
宣告規範:
使用規範:
特點:
介面是抽象行為的」基礎類別「
//介面的宣告
//命名規範 I+帕斯卡命名法
interface IFly
{
void Fly();//方法
string Name//屬性
{
get;
set;
}
int this[int index]//索引器
{
get;
set;
}
event Action doSomthing;//事件委託
}
介面的使用---類的繼承
//介面的使用
class Animal
{
}
class Person:Animal,IFly
{
//實現介面方法也可以加virtual來實現
public virtual void Fly()
{
}
public string Name
{
set;
get;
}
public int this[int index]
{
get
{
return 0;
}
set
{
}
}
public event Action doSomething;
}
介面的使用---介面的繼承
介面繼承基礎類別介面之後,不需要實現介面中的內容(抽象繼承抽象,還是抽象)
等到最後類來具體實現
//介面繼承介面
interface IWalk
{
void Walk();
}
interface IMove:IFly,IMove
{
}
//必須實現所有相關的
//繼承來的抽象內容(介面,介面的父介面中的成員)
class Test:IMove
{
public int this[int index] {
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public string Name {
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public event Action doSomthing;
public void Fly()
{
throw new NotImplementedException();
}
public void Walk()
{
throw new NotImplementedException();
}
}
顯示實現介面
//介面的使用--當作容器 父類別裝子類
interface IAtk
{
void Atk();
}
interface ISuperAtk
{
void Atk();
}
//顯示實現介面
class Player : IAtk, ISuperAtk
{
//遇到相同方法名字
//顯示實現介面 就是用 介面名.行為名 去實現
void IAtk.Atk()
{
}
void ISuperAtk.Atk()
{
}
public void Atk()
{
}
}
class Progarm
{
static void Main(string[] args)
{
IFly f = new Person();
//里氏替換原則
IMove im = new Test();
IFly ifly = new Test();
IWalk iw = new Test();
IAtk ia = new Player();
ISuperAtk isa = new Player();
ia.Atk();
isa.Atk();
Player p = new Player();
(p as IAtk).Atk();//IAtk的
(p as ISuperAtk).Atk();//ISuperAtk的Atk
p.Atk();//自己的Atk
}
}
*密封方法(瞭解)
sealed 修飾的重寫方法,子類不會被重寫方法
namespace
string 本質是char[]陣列 可以有
string ss="Tony",char[0]='T'
字串的拼接
正向查詢字元的位置 IndexOf()
反向查詢字串的位置 LastIndexOf()
移除指定位置後的字元 Remove(index)//注意接受返回值
字串的替換
大小寫轉換
字串的擷取
字串的切割 str.Split(',');按照,切割
字串頻繁拼接使用StringBuilder,不會再次頻繁的建立新的物件,減少垃圾產生。
容量問題:初始時候本身有一定容量,在容量允許範圍內,直接儲存。
超過容量之後,會以2倍大小擴容。相對於string每一次更改便會新建物件,可減少垃圾產生。
//StringBuilder
StringBuilder str=new StringBuilder("My Name is Tony");
//獲取容量
str.Capacity;
//增加
str.Append("Chang");
str.AppendFormat("{0}{1}",123,456);
//插入
str.Insert(0,"Hello");
//刪除
str.Remove(0,10);
//清空
str.Clear();
//查
str[1];
//替換
str.Replace("Name"."name");
//重新賦值
str.Clear();
str.Append("Hello World");
//equals
if(str.Equals("123456"))
{
}
String 還是StringBuilder?
String的方法種類較多,使用更加方便和靈活,但效能上不如StringBuilder,不如StringBuilder產生垃圾少
需要頻繁修改的字串選用StringBuilder更好些。
如何優化記憶體?
如何選擇結構體和類:
相同點:
區別:
如何選擇抽象類與介面
表示物件的選用抽象類,表示行為拓展的用介面。不同物件的相同行為,我們可以抽象出行為,用介面來實現。
總目標:高內聚、低耦合
減少類內部對其它類的呼叫,減少模組與模組之間的互動複雜度。