内存空间分为堆空间和栈空间。栈空间比较小,但是读取速度快;堆空间比较大,但是读取速度慢。
GC Garbage Collector 垃圾回收器
CLR的GC就是内存管理机制,会删除堆中已经没有引用的内容,使得空间可以重复使用。
值类型只需要一段单独的内存,用于存储实际的数据(单独定义的时候放在栈中)。
引用类型需要两端内存——第一段存储食记的数据,它总是位于堆中;第二段是一个引用,指向数据在堆中的存放位置。
注意:
当我们使用引用类型赋值的时候,其实是赋值的引用类型的引用(即将栈中的内存地址赋值,从而改变其对应的引用)。
如果数组是一个值类型的数组,那么数组中直接存储值;如果是一个引用类型的数组(数组中存储的是引用类型),那么数组中存储的是引用(内存地址)。
class Vector3
{
public int x, y, z;
}
注意对以下五个例子的理解
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
Test3();
Test4();
Test5();
}
static void Test1()
{
int i = 34;
int j = 34;
int temp = 34;
char c = 'a';
bool b = true;
}
static void Test2()
{
int i = 34;
int j = 234;
string name = "LJY";
}
static void Test3()
{
string name = "LJY";
string name2 = "Goddy";
name = name2;
name = "Blueekyyy";
}
static void Test4()
{
Vector3 v = new Vector3();
v.x = 100;
v.y = 100;
v.z = 100;
Vector3 v2 = new Vector3();
v2.x = 200;
v2.y = 200;
v2.z = 200;
v2 = v;
v2.x = 300;
Console.WriteLine(v.x);
}
static void Test5()
{
Vector3[] vArray = new Vector3[] { new Vector3(), new Vector3(), new Vector3() };
Vector3 v1 = vArray[0];
vArray[0].x = 100;
v1.x = 200;
Console.WriteLine(vArray[0].x);
}
实现继承:
表示一个类型派生于一个基类型,它拥有该基类型的所有成员字段和函数。在实现继承中,派生类型采用基类型的每个函数的实现代码,除非在派生类型的定义中指定重写某个函数的实现代码。
接口继承:
表示一个类型只继承了函数的签名,没有继承任何实现代码。在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。
注意:
父类声明的对象,可以使用子类去构造,此时该对象虽然是使用父类进行声明的,但因为其使用了子类构造,所以本质上是一个子类类型的对象,可以通过强制类型转换成子类类型。但子类声明的对象不可以通过父类构造,因为子类的功能比父类强大,父类较小。
一个对象是什么类型的,主要看它是通过什么构造的(通过子类构造就是子类类型,通过父类构造就是父类类型)。
例如:
//父类是Enemy,子类是Boss
static void Main(string[] args)
{
Enemy enemy;
enemy = new Boss();//父类声明的对象,可以使用子类去构造
Boss boss = (Boss)enemy;//使用强制类型转换将对象转换为子类类型
boss.Attack();//从而该父类声明的变量可以调用子类中的函数
}
把一个基类函数声明为virtual,就可以在任何派生类中重写该函数。在派生类中重写另外一个函数时,要使用override关键字显示声明。我们在子类里面重写虚函数之后,用子类声明并构造的对象调用时,调用的都是重写之后的方法。但如果用父类声明并构造的对象调用该方法,调用的还是父类中原本的虚函数(跟子类没有任何关系)。
注意:
成员修饰符virtual必须位于成员类型和名称之前
如果签名相同(即)的方法在基类和派生类中都进行了声明,但是该方法没有分别声明为virtual和override,派生类就会隐藏基类方法。要使用new关键字进行声明。
例如:
class Vector3
{
public int x, y, z;
public void Move()
{
}
}
class Vector4:Vector3
{
static new void Move()
{
}
}
当子类里面有一个签名和父类相同的方法时,就会把父类中的方法隐藏。如果使用子类声明的对象,调用隐藏方法会调用子类的,如果使用父类声明的对象,调用隐藏方法会调用父类的。
this可以访问当前类中定义的字段、属性和方法,有没有this都可以访问(有this可以让编译器给出提示),另外当方法的参数与字段重名的时候,使用this可以表明访问的是类中的字段,base可以调用父类中的公有方法和字段,有没有base都可以访问(但加上base.IED工具会给出提示,把所有可以调用的字段和方法罗列出来方便选择)。
【当方法的参数与字段重名的时候,使用this可以表明访问的是类中的字段】例如:
class Vector3
{
public int x, y, z;
public void Set(int x,int y,int z)
{
this.x = x;
this.y = y;
this.z = z;
}
}