111,面向对象
1,面向过程编程:是一种以过程为中心的编程思想分析出解决问题所需要的步骤然后用函数把步骤一步一步实现使用的时候,一个一个依次调用。
2,面向对象编程:面向对象是一种对现实世界理解和抽象的编程方法,把相关的数据和方法组织为一个整体来看待。从更高的层次来进行程序开发更贴近事物的自然运行模式
3,封装:用程序语言来形容对象。
继承:复用封装对象的代码;儿子继承父亲,复用现成代码
多态:同样行为的不同表现,儿子继承父亲的基因但是有不同的行为表现
面向对象编程思想就是:万物皆对象。用程序来抽象(形容)对象,用面向对象的思想来编程。
222,类和对象
- 什么是类
具有相同特征,具有相同行为,一类事物的抽象类是对象的模板。可以通过类创建出对象
类的关键词 :class
2.类声明在namespace里面
3. 类声明的语法
class类名
{
特征一成员变量
行为一成员方法
保护特征一成员属性
构造函数和析构函数
索引器
运算符重载
静态成员
}
4,什么是(类)对象
是在方法里面定义:
基本概念:类的声明 和 类对象(变量)声明是两个概念。类的声明类似 (枚举 和 结构体的声明)。相当于声明了一个自定义变量类型
而对象 是类创建出来的。相当于声明一个指定类的变量。类创建对象的过程 一般称为实例化对象。。类对象 都是引用类型的
5.实例化对象基本语法
是在方法里面定义:
类名 变量名;
类名 变量名 = nu11;(nu11代表空)
类名 变量名 = new 类名();
6.实例化对象
是在方法里面定义:
Person p;
Person p2= nu11;//nu11 代表空 不分配堆内存空间
Person p3= new Person();//相当于一个人对象
Person p4 = new Person();//相当于又是一个人对象!
注意:虽然他们是来自一个类的实例化对象。但是他们的 特征 行为等等信息 都是他们独有的。不要觉得他们是共享了数据 两个彼此没有关系。
Machine m = new Machine();
333,成员变量和访问修饰符
1,访问修饰符
public - 公共的 自己(内部)和别人(外部)都能访问和使用
private - 私有的 自己(内部)才能访问和使用 不写 默认为private
protected - 保护的 自己(内部)和子类才能访问和使用
目前决定类内部的成员 的 访问权限
注意:如果要在类中声明一个和自己相同类型的成员变量时,不能实例化。
2,成员变量的使用和初始值
值类型来说 数字类型 默认值都是0 bool类型 false 引用类型的 null
默认值的小技巧:直接打印运行就看到了。
Console.WriteLine(default(Person))
333,成员方法的声明和封装
成员方法声明
基本概念:成员方法(函数】用来表现对象行为
1.声明在类语句块中
2.是用来描述对象的行为
3.规则和函数声明规则相同
4.受到访问修饰符规则影响
5.返回值参数不做限制
6.方法数量不做限制
注意:
1.成员方法不要加static关键字
2.成员方法 必须实例化出对象 再通过对象来使用 相当于该对象执行了某个行为
3.成员方法 受到访问修饰符影响
成员方法的使用
成员方法 必须实例化出对象 再通过对象来使用 相当于该对象执行了某个行为
示例:
class Person
{
public int age;
public string name;
public Person 【】 friends;//数组
public void Speak(string str)
{
Console.WriteLine(“{0}说{1}”, name,str);
}
数组
public void AddFriend(Person)
{
if(friends == null)
{
friends = new Person[]{p };
}
else
{
扩容(数组扩充)
Person[] newFriends=newPerson[friends.Length + 1];
for(int i=0;i<friends.Length; i++)
{
newFriends[i]= friends[i];
}
newFriends[newFriends.Length-1]= p;
friends = newFriends;
}
}
//成员方法 必须实例化出对象 再通过对象来使用 相当于该对象执行了某个行为
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.name = “lalala”;
p.age = 11;
p.Speak(“雨雨雨雨雨雨”);
Person p2 = new Person();
p2.name = “lalala2”;
p2.age = 21;
p.AddFriend(p2);
for(int i = 0; i < p.friends.Length; i++)
{
cw(p.friends[i].name);
}
}
}
444. 构造,析构,垃圾回收
1,基本概念
在实例化对象时 会调用的用于初始化的函数。如果不写 默认存在一个无参构造函数。
构造函数的写法:1.没有返回值2.函数名和类名必须相同3.没有特殊需求时 一般都是public的注意:类中是允许自己声明无参构造函数的 结构体是不允许4.构造函数可以被重载5.this代表当前调用该函数的对象自己
注意: 如果不自己实现无参构造函数而实现了有参构造函数会失去默认的无参构造
可以通过this 重用构造函数代码:
访问修饰符 构造函数名(参数列表):this(参数1,参数2…)
2,析构函数基本概念
当引用类型的堆内存被回收时,会调用该函数。对于需要手动管理内存的语言(比如C++),需要在析构函数中做一些内存回收处理。但是C#中存在自动垃圾回收机制Gc。所以我们几乎不会怎么使用析构函数。除非你想在某一个对象被垃圾回收时,做一些特殊处理
注意:在Unity开发中析构函数几乎不会使用,所以该知识点只做了解即可。
/基本语法
~类名()
{
}
析构函数 是当垃圾 真正被回收的时候 才会调用的函数
~Person()
{
}
3,垃圾回收
垃圾回收,英文简写Gc(Garbage collector)
垃圾回收的过程是在遍历堆(Heap)上动态分配的所有对象。通过识别它们是否被引用来确定哪些对象是垃圾,哪些对象仍要被使用所谓的垃圾就是没有被任何变量,对象引用的内容垃圾就需要被回收释放。垃圾回收有很多种算法,比如引用计数(Reference counting)标记清除(Mark Sweep)标记整理(Mark compact)复制集合(copy Collection)
注意:GC只负责堆(Heap)内存的垃圾回收。引用类型都是存在堆(Heap)中的,所以它的分配和释放都通过垃圾回收机制来管理。。栈(stack)上的内存是由系统自动管理的。。值类型在栈(stack)中分配内存的,他们有自己的生命周期,不用对他们进行管理,会自动分配和释放
C#中内存回收机制的大概原理
0代内存 1代内存 2代内存
代的概念:
代是垃圾回收机制使用的一种算法((分代算法)。新分配的对象都会被配置在0代内存中。每次分配都可能会进行垃圾回收以释放内存(0代内存满时)
在一次内存回收过程开始时,垃圾回收器会认为堆中全是垃圾,会进行以下两步:
1.标记对象 从根(静态字段、方法参数)开始检査引用对象,标记后为可达对象,未标记为不可达对象不可达对象就认为是垃圾
2.搬迁对象压缩堆(挂起执行托管代码线程)释放未标记的对象 搬迁可达对象 修改引用地址.。。
大对象总被认为是第二代内存,目的是减少性能损耗,提高性能.。不会对大对象进行搬迁压缩 85000字节(83kb)以上的对象为大对象
堆 heap 栈stack
555,成员属性
1,基本概念
1.用于保护成员变量
2.为成员属性的获取和赋值添加逻辑处理
3.解决”3P“的局限性
public-内外访问
private-内部访问
protected-内部和子类访问
属性可以让成员变量在外部
只能获取 不能修改 或者 只能修改 不能获取
2语法:
示例:
访问修饰符 属性类型 属性名
{
get{}
set{}
}
实例:
class Person
{
private string name;
private int age;
//属性使用:帕斯卡命名法。
public string Name
{
get
{
//可在返回之前添加一些逻辑规则。
//意味着这个属性可以获取内容
return name;
}
set
{
//可以设置之前添加的一些逻辑规则
//value关键字 用于表示 外部传入的值。
name = value;
}
}
}
3成员属性中
get和set前可以加访问修饰符
注意:1.默认不加 会使用属性申明时的访问权限2.加的访问修饰符要低于属性的访问权限3.不能让get和set的访问权限都低于属性的权限
4只有一个时 没必要在前面加访问修饰符
public bool sex
{
get
{
return sex;//只能得到她
}
}
5.自动属性
作用:外部能得不能改的特征。如果类中有一个特征是只希望外部能得不能改的又没什么特殊处理。那么可以直接使用自动属性
public bool sex
{
get;
set;
}
总结:
1.成员属性概念:一般是用来保护成员变量的
2.成员属性的使用和变量一样 外部用对象点出
3.get中需要return内容:set中用value表示传入的内容
4.get和set语句块中可以加逻辑处理
5.get和set可以加访问修饰符,但是要按照一定的规则进行添加
6.get和set可以只有一个
7.自动属性是属性语句块中只有get和set,一般用于 外部能得不能改这种情况
666,封装索引器
概念:让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观,更容易编写。
访问修饰符 返回值 this[参数类型 参数名,参数类型 参数名…]
{
//内部的写法和规则和索引器相同
get{}
set{}
}
可以重载
//总结
//索引器对于我们来说的主要作用
//可以让我们以中括号的形式范围自定义类中的元素 规则自己定 访问时和数组一样
//比较适用于 在类中有数组变量时使用 可以方便的访问和进行逻辑处理
结构体支持使用索引器。
777,封装-静态成员
1.静态成员基本概念
//静态关键字static
//用static修饰的 成员变量、方法、属性等称为静态成员
静态成员的特点是:直接用类名点出使用
2.早已出现的静态成员
3.自定义静态成员
在类里面封装的
class aaa
{
static public floate PI=3.14f;
public static flaot
{
}
}
静态函数时公共的。。
4.为什么可以直接点出来使用
程序中是不能无中生有的
我们要使用的对象,变量函数都是要在内存中分配内存空间的.之所以要实例化对象,目的就是分配内存空间,在程序中产生一个抽象的对象
静态成员的特点:程序开始运行时 就会分配内存空间。所以我们就能直接使用。
静态成员和程序同生共死:只要使用了它,直到程序结束时内存空间才会被释放:所以一个静态成员就会有自己唯一的一个“内存小房间”。这让静态成员就有了唯一性。在任何地方使用都是用的小房间里的内容,改变了它也是改变小房间里的内容。
6.静态函数中不能使用非静态成员
不能直接使用 非静态成员 否则会报错
成员变量只能将对象实例化出来后 才能点出来使用 不能无中生有
8.静态成员对于我们的作用
静态变量:1.常用唯一变量的中明2.方便别人获取的对象申明
静态方法:常用的唯一的方法申明 比如 相同规则的数学计算相关函数
9.常量和静态变量
const(常量)可以理解为特殊的static(静态)
相同点:他们都可以通过类名点出使用
不同点:1.const必须初始化,不能修改 static没有这个规则2.const只能修饰变量、static可以修饰很多3.const一定是写在访问修饰符后面的,static没有这个要求
888. 静态类
概念用static修饰的类
特点只能包含静态成员。不能被实例化
作用1.将常用的静态成员写在静态类中 方便使用2.静态类不能被实例化,更能体现工具类的 唯一性
比如 console就是一个静态类。
static class00s
{
//静态成员变量
public static int testIndex = 0,
public static void TestFun()
{
}
public static int TestIndex
{
get;
set;
}
999静态构造函数
概念在构造函数加上 static 修饰
特点1.静态类和普通类都可以有2.不能使用访问修饰符3.不能有参数4.只会自动调用一次
作用在静态构造函数中初始化 静态变量
使用1.静态类中的静态构造函数
示例:
static class staticclass
{
public static int testInt = 100;
public static int testInt2 = 100;
0 个引用
static staticclass()
{
Console.WriteLine("“静态构造函数”)
}
}
2.普通类中的静态构造函数(第一次使用里面的内容时,会自动调用)
class Test
{
public static int testInt = 200;
0 个引用
static Test()
{
Console.WriteLine(“静态构造”);
}
public fest()
{
Console.WriteLine(“普通构造”)
}
101010拓展方法,
概念:为现有非静态 变量类型 添加新方法
作用1.提升程序拓展性2.不需要再对象中重新写方法3.不需要继承来添加方法4.为别人封装的类型写额外的方法
特点1.一定是写在静态类中2.一定是个静态函数3.第一个参数为拓展目标!4.第一个参数用this修饰
语法:访问修饰符 static 返回值 函数名(this 拓展类名 参数名,参数类型 参数名,参数类型 参数名…
为int拓展了一个成员方法:成员方法 是需要 实例化对象后 才 能使用的。。value 代表 使用该方法的 实例化对象
public static void speakValue(this int value)
{
//拓展的方法 的逻辑
Console.WriteLine("唐老狮为int拓展的方法”+value);
}
:运算符重载
概念:让自定义类和结构体,能够使用运算符。
使用关键字:operator
特点:1.一定是一个公共的静态方法2.返回值写在operator前3.逻辑处理自定义
作用:让自定义类和结构体对象可以进行运算
注意:1.条件运算符需要成对实现2.一个符号可以多个重载3.不能使用ref和out
语法:public static 返回类型 operator 运算符(参数列表)
实例:
class Point
{
public int x;
public int y;
public static Point operator +(Point p1, Point p2)
{
Point p = new Point();
p.x = p1.x + p2.x;
p.y = p1.y + p2.y;
return p;
}
public static Point operator +(Point p1, int value)
{
Point p = new Point();
p.x = p1.x +value;
p.y = p1.y + value;
return p;
}
//int在前和在后
public static Point operator +(int value,Point p1 )
{
Point p = new Point();
p.x = p1.x + value;
p.y = p1.y + value;
return p;
}
//可重载运算符
//算术运算符
//需要两个参数还是一个参数
public static Point operator -(Point p1, Point p2)
{
return null;
}
public static Point operator *(Point p1, Point p2)
{
return null;
}
public static Point operator /(Point p1, Point p2)
{
return null;
}
public static Point operator %(Point p1, Point p2)
{
return null;
}
public static Point operator ++(Point p1)
{
return null;
}
public static Point operator --(Point p1)
{
return null;
}
//逻辑运算符:
public static Point operator !(Point p1)
{
return null;
}
//位运算符
public static Point operator |(Point p1, Point p2)
{
return null;
}
public static Point operator &(Point p1, Point p2)
{
return null;
}
public static Point operator ^(Point p1, Point p2)
{
return null;
}
//取反(0,1)
public static Point operator ~(Point p1)
{
return null;
}
public static Point operator <<(Point p1,int num)
{
return null;
}
//条件运算符
//相关符号需要配对实现
public static Point operator >=(Point p1, Point p2)
{
return null;
}
public static Point operator <=(Point p1, Point p2)
{
return null;
}
public static Point operator >(Point p1, Point p2)
{
return null;
}
public static Point operator <(Point p1, Point p2)
{
return null;
}
//不可重载运算符:
//逻辑与&&逻辑或||
//索引符[]
//强转运算符()
//特殊运算符
//点。 三目运算符 ?:赋值运算符=
}
internal class Program
{
static void Main(string[] args)
{
Point p = new Point();
p.x=1; p.y=1;
Point p2 = new Point();
p2.y=1;p2.x=1;
Point p3=p+p2;
//02按照顺序(上面必须有重载)
Point p4=p3+2;
Point p5=2+p3;
}
}
121212内部类和分布类
面对对象————继承
继承的规则
概念:一个类A继承一个类的。。类A将会继承类B的所有成员。A类将拥有B类的所有特征和行为
被继承的类称为 父类、基类、超类
继承的类称为子类、派生类
子类可以有自己的特征和行为
特点1.单根性 子类只能有一个父类2.传递性 子类可以间接继承父类的父类
class ChineseTeacher : TeachingTeacher
{
public void Skill()
{
Console.WriteLine(“nianainia”);
}
里氏替换规则
概念:任何父类出现的地方,子类都可以替代
重点:语法表现一父类容器装子类对象,因为子类对象包含了父类的所有内容
作用:方便进行对象存储和管理
1里氏替换原则 用父类容器 装载子类对象
GameObject player = new Player();
is和as
2基本概念 is:判断一个对象是否是指定类对象返回值:boo1 是为真 不是为假
if( player is Player )
{
}
else if( player is Monster )
{
}
3as:将一个对象转换为指定类对象
// 返回值:指定类型对象
// 成功返回指定类型对象,
,失败返回nu11
//基本语法
// 类对象 is 类名
该语句块 会有一个bool返回值 true和false
// 类对象 as 类名
该语句块 会有一个对象返回值 对象和nu11
if( player is Player )
{
Player p= player as Player;
p.PlayerAtk();
(player as Player).PlayerAtk();
}
继承中的构造函数
特点:当申明一个子类对象时,先执行父类的构造函数再执行子类的构造函数
注意:1.父类的无参构造 很重要2.子类可以通过base关键字 代表父类 调用父类构造
无参构造函数很重要
子类实例化时 默认自动调用的 是父类的无参构造 所以如果父类无参构造被顶掉 会报
万物之父
关键字:object
概念:object是所有类型的基类,它是一个类(引用类
作用:1.可以利用里氏替换原则,用object容器装所有对象2.可以用来表示不确定类型,作为函数参数类型
万物之父的使用:
Father f = new Son();
if( f is son )
{
(f as son).Speak();
}
//引用类型
object o= new son();
//用is as 来判断和转换即可
if( o is son )
{
(o as son).Speak();
}
//值类型
object o2 = 1f;
//用强转
float :fl =(float)o2;
//特殊的string类型
object str=“123123”;
string str2 = str as string; //tostring
//数组
object arr= new int【10】;
int【】arr=(int【】)arr;
装箱拆箱
发生条件:用bbject存值类型(装箱),再把object转为值类型(拆箱)
装箱:把值类型用引用类型存储。栈内存会迁移到堆内存中
拆箱:把引用类型存储的值类型取出来。堆内存会迁移到栈内存中
好处:不确定类型时可以方便参数的存储和传递
坏处:存在内存迁移,增加性能消耗
实例:
//装箱
object v=3;
//拆箱
int intValue =(int)v;
131313 面向对象–多态
Vob
多态的概念:多态按字面的意思就是“多种状态”。让继承同一父类的子类们 在执行相同方法时有不同的表现(状态)
主要目的:同一父类的对象 执行相同行为(方法)有不同的表现
解决的问题:让同一个对象有唯一行为的特征
多态的实现
vob
v:virtual(虚函数)–可以被子类重写
o:override(重写)
b:base(父类)
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.Atk();
Console.WriteLine(“玩家对象进行攻击”);
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine();
GameObject p = new Player(“yaya”);
p.Atk();
// (p as Player).Atk();
}
}
抽象类和抽象方法
抽象类
概念:被抽象关键字abstract修饰的类
特点:1.不能被实例化的类2.可以包含抽象方法3.继承抽象类必须重写其抽象方法
抽象函数 又叫 纯虚方法
用 abstract关键字修饰的方法
特点:1.只能在抽象类中申明2.没有方法体3.不能是私有的4.继承后必须实现 用override重写
虚方法是可以由我们子类选择性来实现的 抽象方法必须要实现
虚方法和抽象方法 都可以被子类无限的 去重写
密封方法
密封方法基本概念:用密封关键字sealed 修饰的重写函数
作用:让虚方法或者抽象方法之后不能再被重写
特点:和override一起出现
接口
接口的概念:接口是行为的抽象规范,它也是一种自定义类型。
关键字 :interface
接口声明的规范
1.不包含成员变量
2.只包含方法、属性、索引器、事件
3.成员不能被实现
4.成员可以不用写访问修饰符,不能是私有的
5.接口不能继承类,但是可以继承另一个接口
接口的使用规范:1.类可以继承多个接口2.类继承接口后,必须实现接口中所有成员
特点:1.它和类的申明类似2.接口是用来继承的3.接口不能被实例化,但是可以作为容器存储对象
接口关键字:interface
语法:
interface 接口名
{
}
一句话记忆:接口是抽象行为的“基类”
接口命名规范 帕斯卡前面加个I
接口用来继承
1.类可以继承1个类,n个接口
2.继承了接口后 必须实现其中的内容 并且必须是public的
3.实现的接口函数,可以加v再在子类重写
4.接口也遵循里氏替换原则
接口可以继承接口
接口继承接口时,不需要实现。待类继承接口后 类自己去实现所有内容
显示实现接口
当一个类继承两个接口。但是接口中存在着同名方法时
注意:显示实现接口时 不能写访问修饰符
注意:
1.接口值包含 成员方法、属性、索引器、事件,并且都不实现,都没有访问修饰符
2.可以继承多个接口,但是只能继承一个类
3.接口可以继承接口,相当于在进行行为合并,待子类继承时再去实现具体的行为
4.接口可以被显示实现 主要用于实现不同接口中的同名函数的不同表现
5.实现的接口方法 可以加 virtua1关键字 之后子类 再重写
interface IFly
{
void Fly();
string Name
{
get;
set;
}
int this[int index]
{
get; set;
}
event Action doSomthing;
}
//接口是用来继承
class Animal
{
}
2.继承了接口后 必须实现其中的内容 并且必须是public的
class Person : Animal, IFly
{
3.实现的接口函数,可以加v再在子类重写
public void Fly()
{
}
public string Name
{
get;
set;
}
public int this[int index]
{
get
{
return 0;
}
set
{
}
}
public event Action doSomthing;
}
//接口继承接口时,不需要实现
//待类继承接口后,类自己去实现所有内容
interface IWalk
{
void Walk();
}
interface IMove:IFly, IWalk
{
}
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 Plater : IAtk, ISuperAtk
{
显示实现接口,就是用,接口名”点。“行为名去实现
void IAtk.Atk()
{
throw new NotImplementedException();
}
void ISuperAtk.Atk()
{
throw new NotImplementedException();
}
public void Atk()
{
}
}
class Program
{
static void Main(string[] args)
{
4.接口也遵循里氏替换原则
IFly f = new Person();//装装载 子类对象
IWalk walk = new Test();
IMove move = new Test();
IFly fly = new Test();
IAtk ia = new Plater();
ISuperAtk isa = new Plater();
Plater p = new Plater();
(p as IAtk).Atk();
}
}
}
命名空间
概念:名空间是用来组织和重用代码的
作用:就像是一个工具包,类就像是一件一件的工具,都是声明在命名空间中的
不同命名空间中相互使用,需要引用命名空间或者指明出处。
例子:using MyGame
MyGame.GanmeObject g = new GameObject();
不同命名空间中可以有同一种类。这个就要知名命名空间的出处。
例子:
MyGame.GanmeObject g = new GameObject();
命名空间可以包裹命名空间
例子:
namespace MyGame
{
namespace UI
{
}
namesp Game
{
}
}
访问修饰符:
public
internal
abstract 抽象类
sealed 密封
partial 分布类
object 方法:
静态方法 Equals 判断两个对象是否相等。最终的判断权,交给左侧对象的Equa1ls方法。不管值类型引用类型都会按照左侧对象Equals方法的规则来进行比较
Console.WriteLine(object.Equals(1,1));
Test t= new Test();
Test t2 =t;
Console.WriteLine(object.Equals(t,t2));
静态方法ReferenceEquals,比较两个对象是否是相同的引用,主要是用来比较引用类型的对象。。值类型对象返回值始终是false://比引用
Console.WriteLine(object.ReferenceEquals(t,t2));
object中的成员方法
//普通方法GetType:该方法在反射相关知识点中是非常重要的方法,之后我们会具体的讲解这里返回的Type类型。该方法的主要作用就是获取对象运行时的类型Type,通过Type结合反射相关知识点可以做很多关于对象的操作。
Test t= new Test();
Type type =t.GetType()
//普通方法Memberwiseclone:该方法用于获取对象的浅拷贝对象,口语化的意思就是会返回一个新的对象,但是新对象中的引用变量会和老对象中一致。
class Test
{
public int i = 1;
public Test2 t2 = new Test2();
public Test clone()
{
return Memberwiseclone() as Test;
}
}
class Test2
{
public int i = 2;
}
Test t2 =t.clone();
Console.WriteLine("克隆对象后”);
Console.WriteLine(“t.i=”+ t.i);
Console.WriteLine(“t.t2.i =”
- t.t2.i);
Console.WriteLine(“t2.i=”+t2.i);
Console.WriteLine("t2.t2.i = - t2.t2.i);
t2.i = 20;
t2.t2.i = 21;
Console.WriteLine(“改变克隆体信息后”);
Console.WriteLine(“t.i=”+ t.i);
Console.WriteLine(“t.t2.i=”+t.t2.i);
Console.WriteLine(“t2.i=”+ t2.i);
Console.WriteLine(“t2.t2.i=”+t2.t2.i);
object中的虚方法
虚方法Equals:默认实现还是比较两者是否为同一个引用,即相当于ReferenceEquals。但是微软在所有值类型的基类system.ValueType中重写了该方法,用来比较值相等。我们也可以重写该方法,定义自己的比较相等的规则
虚方法GetHashcode:该方法是获取对象的哈希码(一种通过算法算出的,表示对象的唯一编码,不同对象哈希码有可能一样,具体值根据哈希算法;我们可以通过重写该函数来自己定义对象的哈希码算法,正常情况下,我们使用的极少,基本不用。
虚方法Tostring该方法用于返回当前对象代表的字符串,我们可以重写它定义我们自己的对象转字符串规则。该方法非常常用。当我们调用打印方法时,默认使用的就是对象的Tostring方法后打印出来的内容
/总结
/1.虚方法 tostring 自定字符串转换规则
/2.成员方法 GetType 反射相关
/3.成员方法 Memberwiseclone 浅拷贝
/4.虚方法 Equals 自定义判断相等的规则
string
注意:所有的方法记得重新赋值,否则不起作用。
1,字符串指定位置获取:
A:字符串本质是char数组
例子:
string str = “ABC";
CW(str[0]);//打印出来:A
B:转为char数组
例子:
char[] chars = str.ToCharArray();
for(i=0;i<str.Length;i++)
{
cw(str[i]);
}
2.字符串拼接
str= string.Format(“ {0},{1}”,1,22);
cw(str); // 1,22
3,正向查找字符串位置
str = “我是谁呀你”;
int index = str.IndexOf("谁“);
cw(index);
注意:如果查找的字符串没有则显示”-1“
4,反向查找指定字符串位置
例子
str = “我是谁呀你”;
int index = str.LastIndexOf("谁“);
cw(index);
5.移除指定位置后的字符
str = “我是谁呀你”;
int index = str.Remove(4);
cw(index);
int index = str.Remove(1,2);//执行的两个参数,参数1:开始位置;参数2:字符个数)
cw(index);
6,替换指定字符串
str = “我是谁呀你”;
int index = str.Replace(”啊啊啊啊“);
cw(index);
7,大小写转换
小转大:
str = ”a,b,c,d";
str1=str.ToUper();
cw(str1);
大转小:
str = ”A,B,C,D";
str1=str.ToLower();
cw(str1);
8.字符串截取
注意:截取从指定字符串位置之后的字符串。
str = “我是谁呀你”;
int index = str.SubString(2);
cw(index);//我是谁
int index = str.SubString(1,2);//执行的两个参数,参数1:开始位置;参数2:截取的字符个数)
cw(index);// 我呀你
9,字符串切割
str = “1,2,3,4,5,6”;
string [] str = str.Split(‘,’);
for(i=0;i<str.Length;i++)
{
cw(str);
}
打印出来:
1
2
3
4
5
6
这里用到配表居多。
stringbuilder
C#提供的一个用于处理字符串的公共类
//主要解决的问题是:
//修改字符串而不创建新的对象,需要频繁修改和拼接的字符串可以使用它,可以提升性能
//使用前 需要引用命名空间
//stringBuilder存在一个容量的问题,
每次往里面增加时 会自动扩容
//获得容量
Console.WriteLine(str.Capacity);
//获得字符长度
Console.WriteLine(str.Length);
增查删清查改替换
1,增加
直增:str.Appand(“111”);
拼接增:str.AppendFormat(“{0}{1}”,100,99);
2,插入
str。Insert (0,“里”)//在第0个位置插入一个字符串“里”
3,删减
str.Remove(0,10);//从第0个位置开始删掉10个字符串
4,清空
str.Clear();
5,查看
cw(str[0]);//打印出来这个位置的字符串是什么
6,改
str[0]=‘A’;//把字符串的第0位修改为A
7,替换
str.Replace(“1”,“A”);//把字符串1替换成A
8,重新赋值
先清空在添加
str.Clear();
str.Appand(“111”);
cw(str);
9,判断是否相等
str=“123”;
if(str.Equals(“123”))
{
cw(“xiangdeng)”
}
结构体和类的区别
区别概述
结构体和类最大的区别是在存储空间上的,因为结构体是值,类是引用。因此他们的存储位置一个在栈上,一个在堆上‘
结构体和类在使用上很类似,结构体甚至可以用面向对象的思想来形容一类对象。
结构体具备着面向对象思想中封装的特性,但是它不具备继承和多态的特性,因此大大减少了它的使
由于结构体不具备继承的特性,所以它不能够使用protected保护访问修饰符。
细节区别
1.结构体是值类型,类是引用类型
2.结构体存在栈中,类存在堆中
3.结构体成员不能使用protected访问修饰符,而类可以
4.结构体成员变量申明不能指定初始值,而类可以
5.结构体不能申明无参的构造函数,而类可以
6.结构体申明有参构造函数后,无参构造不会被顶掉
7.结构体不能申明析构函数,而类可以
8.结构体不能被继承,而类可以
9.结构体需要在构造函数中初始化所有成员变量,而类随意
10.结构体不能被静态static修饰(不存在静态结构体),而类可以
11.结构体不能在自己内部申明和自已一样的结构体变量,而类可以
结构体的特别之处
结构体可以继承 接口 因为接口是行为的抽象
如何选择结构体和类
1.想要用继承和多态时,直接淘汰结构体,比如玩家、怪物等等
2.对象时数据集合时,优先考虑结构体,比如位置、坐标等等
3.从值类型和引用类型赋值时的区别上去考虑,比如经常被赋值传递的对象,并且
改变赋值对象,原对象不想跟着变化时,就用结构体。比如坐标、向量、旋转等等
抽象类和接口的区别
抽象类和抽象方法:abstract修饰的类和方法
抽象类 不能实例化是个纯虚函数必须在子类中实现
抽象方法只能在抽象类中声明
接口interface 自定义类型是行为的抽象不包含成员变量建议不写访问修饰符,默认public仅包含方法、属性、索引器、事件,成员都不能实现
相同点
1.都可以被继承
2.都不能直接实例化
3.都可以包含方法声明
4.子类必须实现未实现的方法
5.都遵循里氏替换原则
区别
1.抽象类中可以有构造函数;接口中不能
2.抽象类只能被单一继承;接口可以被继承多个
3.抽象类中可以有成员变量;接口中不能
4.抽象类中可以申明成员方法,虚方法,抽象方法,静态方法;接口中只能申明没有实现的抽象方法
5.抽象类方法可以使用访问修饰符;接口中建议不写,默认public
如何选择抽象类和接口
表示对象的用抽象类,表示行为拓展的用接口
不同对象拥有的共同行为,我们往往可以使用接口来实现
举个例子:(抽象大,接口小)动物是一类对象,我们自然会选择抽象类;而飞翔是一个行为,我们自然会选择接口。
七大原则
(1)七大原则总体实现目标:高内聚、低耦合。使程序模块的可重用性,移植性增强
(2)七大原则具体内容
单一职责 类被修改的几率很大,因此应该专注于单一的功能
开闭原则 对扩展开发,对修改关闭
里氏替换原则 任何父类出现的地方,子类都可以替代
依赖倒转原则 要依赖于抽象,不要依赖于具体的实现
迪米特原则 一个对象应该对其他对象尽可能少的了解
接口分离原则 一个接口尽量只提供一个对外的功能
合成复用原则 尽量使用对象组合,而不是继承来达到复用的目的
七大原则:
单一职责原则:一个类只处理自己应该处理的内容,不应该啥都写在一起。
关闭原则:对拓展开放,对修改封闭。新加功能尽量使加处理而不是修改代码
里氏原则:任何地方子类都能代替父类,父类容器装子类。
依赖倒转原则:不要依赖具体的实现,要依赖抽象和接口
迪米特法则:一个类尽量减少对别的类的了解。尽量少用别的类和自己关联。
接口隔离原则:一个接口一个行为,不要一个接口N个行为。
合成服用原则:除非设计上需要继承,否则尽量用组合复用形式。