结构体也是可以有构造函数的。
值类型是储存在栈里面的。
结构体也是可以有构造函数的。
值类型是储存在栈里面的。
实现接口,是实现抽象函数
实现接口,实现抽象函数
实现接口,实现抽象函数
实现接口,实现抽象函数
实现ni
捕捉异常
对象和对象对比的是引用(内存地址),而不是参数。
!可以用来取反
!可以用来取反
!可以用来取反
索引器:
private int[] z=new int[10];
public int sy[int i]
{
get{return z[i];}set{z[i]=value;}
}
索引器的声明类似于属性,但使用this关键字和一个或多个参数来表示索引。例如,如果你的类表示一个合计,可以使用整数索引来访问集合中的元素。
在索引器的get访问器中实现获取索引处元素的逻辑,通过return返回相应的值。在set访问器中实现设置索引处元素的逻辑。
索引器可以有多个参数,以支持多维索引或其它复杂的索引方案。
C#还允许你在索引器中使用不同的数据类型作为索引,例如字符串或自定义类型。
接口/interface:
pablic interface 类名{ 不完整的函数 }
定义一个接口在语法上跟定义一个抽象类完全相同,但不允许提供接口中任何成员的实现方式,一般情况下,接口只能包含方法,属性,索引器和事件的声明。
接口不能又构造函数,不能有字段,接口 也不允许运算符重载。
接口定义中不允许声明成员的修饰符,接口成员都是public(公有的)的。
接口的继承:public interface 接口2:接口1
此时在类中继承接口2时,是调用了继承了接口1的接口2。
多态:在父类声明一个对象的时候,可以利用它任意一个子类进行构造或重新构造,这时候这个父类对象可以是多种形态的 简称(多态)
接口/interface:
pablic interface 类名{ 不完整的函数 }
定义一个接口在语法上跟定义一个抽象类完全相同,但不允许提供接口中任何成员的实现方式,一般情况下,接口只能包含方法,属性,索引器和事件的声明。
接口不能又构造函数,不能有字段,接口 也不允许运算符重载。
接口定义中不允许声明成员的修饰符,接口成员都是public(公有的)的。
多态:在父类声明一个对象的时候,可以利用它任意一个子类进行构造或重新构造,这时候这个父类对象可以是多种形态的 简称(多态)
new:隐藏继承的成员。
abstract:创建抽象类和抽象函数。
sealed:修饰密封类和密封函数。(在函数中使用sealed时必须始终与override一起使用,且该函数一定需要是一个重写过的方法,表示不可被再次重写)
const(常量):使用const来声明某个常量字段或常量局部变量,必须在声明常量时赋初值。(不能和static一起使用,常量默认是static的,常量字段只有一个副本。)
static(静态的):
readonly:使用readonly关键字来声明只读字段。
只读字段可以在声明或构造函数中初始化,每个类或构造的实例都有一个独立的副本。可以与static一起使用,声明静态只读字段。
静态只读字段可以在声明或静态构造函数中初始化,静态常量字段只有一个副本。
构造函数是对数据进行初始化的
class Customer
{
public string name;
public string address;
private int age;
public string createTime;
public Customer()
{
Console.WriteLine("这是无参构造函数");
}
Customer c1=new.Customer()
Customer c2=new.Customer()
Customer c3=new.Customer()
F5运行之后就是
这是构造函数
这是构造函数
这是构造函数
public Customer (string a1,string a2,int a3,int a4)
{
name=a1;
address=a2;
age=a3;
createTime=a4;
}
1、如何在子类中调用父类的默认构造函数(无参)
在子类构造函数后面加上:base();//指定调用父类的无参构造函数。
public 子类名():base()
{
}
base()//指定调用无参的构造函数。此时会先调用父类的无参构造函数,然后在调用子类构造函数。
//不加base()的情况下也是默认调用无参的构造函数,如果父类中没有无参的构造函数的情况下会报错。
2、调用有参数的构造函数
设父类构造函数参数为(int i,string z)
public 子类名(int I,string Z):base(I,Z)
{
}
因已在子类构造函数内指定了父类构造函数的参数类型为int和string,又将子类构造函数内的参数放在base()内,那么此时父类内指定对应的构造函数会被base()括号内的参数赋值。
抽象类://abstract
抽象类只有函数定义没有函数体,抽象类是一个不完整的类。
abstract class 类名
{
pritave int Z; //这是一个正常的字段成员
public void 类名()
{
Console.WriteLine("这是一个正常函数");
}
public abstract void 类名();
}
抽象类内可以包含正常的字段成员及函数成员,但抽象函数必须在抽象类里,抽象类为父类,用于子类必须有用此类包含的抽象方法,供子类编辑。
语法规定,只能声明抽象类,但不能使用抽象类直接构造对象。因为不能使用一个不完整的类构造对象。但我们可以使用它的子类构造对象。
实现抽象类:
光标移动到报错上等待错误提示可以快捷操作"实现抽象类"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
密封类和密封方法: //sealed
密封类:
sealed class 类名
{
此时类为密封类,不可被其它类继承。
}
密封方法:
class 派生类
{
public sealed override 函数名
{
此时函数不可以被重写,但仍可被继承
}
}
作用:防止重写某些类导致代码混乱。
作用:商业原因。
隐藏重写方法
基类的函数正常写。
public new void AI()
{
重写方法
}
//添加关键字new可以把原本的函数给隐藏。从而达到重写方法的目的
调用:
基类 Z=new 派生类 //如:派生类中有使用隐藏方法重写的函数
此时调用的是基类方法,并非派生类中新创建的隐藏方法。
原因:此时构造派生类实际上实际上是创建了一个新的同名方法,而并非覆盖基类原有的同名方法。
且编译器只知道"Z"是一个基类类型。因此它只能调用基类中存在的方法。
即使派生类中定义了同一个方法,该方法也不会被调用。(因为基类引用无法访问派生类新增成员。)
虚方法是覆盖,隐藏方法是隐藏
base. //专门(只能) 访问父类里的数据。
protected //保护的,可以让子类访问
实现继承:
派生类:基类
派生类会继承基类所有的字段和函数。在继承中,派生类采用所有基类的代码,除非派生类制定重写某个函数的实现代码。
基类可以有多个派生类
类变量2=类变量1
这种类变量赋值给类变量其实是内存地址赋值,并不是参数赋值(原本类变量2的内存地址与类变量1的内存地址不一致,通过类变量赋值给类变量实际上是赋值了类变量1在栈内的内存地址给类变量2)所以此时更改类变量1或类变量2的参数时,由于两个变量指向同一个堆的内存地址,所以此时类变量1与类变量2的参数都会变更。
GC(垃圾回收)
每一个对象都会被一个变量所引用的,GC对于每一个对象都会有一个计数器表示栈内有几个类变量在引用该对象,每个对象GC都会给它持有一个计数器,堆区内的GC每隔一段时间会检查所有的对象,看那些对象的计数器是否为0。在该对象的计数器为0时会回收该对象所占用的内存区域给回收掉,供新的对象使用。
如何把这个引用给他去掉呢?
类变量=null;
这种情况下可以把该类变量在栈区内的内存地址清空。同时该类变量指向堆区的内存地址计数器-1。
null//空 空引用 空对象
除了数组,类,string其余都是值类型。
值类型和引用类型://枚举对应数字,是一个值类型
值类型(整数 bool struct(结构体) char 小数)
引用类型(string 数组 自定义的类 内置类)
值类型只需要一段单独的内存,用于存储实际的数据,(单独定义的时候放在栈中)
引用类型需要两段内存
第一段存储实际的数据,它总是位于堆中
第二段是一个引用,指向数据在堆中的存放位置(这个引用指的是它的内存地址)
变量名是我们在程序当中使用的
实际使用时每个变量名都会转换成一个内存地址的
整数数组保存在堆里,栈里存在它的内存地址。
每个字符串本质上都是一个常量,都存储在静态存储区内,如(字符串数组、new类的字符串类型参数)都保存在静态存储区。
字符串数组、new类的字符串类型参数,实际上是栈(内存地址)→堆(内存地址)→静态存储区内数据。
为什么string要放在静态存储区,因为每个字符串都是一个常量,不可被修改。更改字符串类型赋值时实际上是修改了该变量栈内指向静态存储区的内存地址。
栈:空间比较小,但读取速度快
堆:空间比较大,但读取速度慢
栈只能从最上面的开始删除(先进后出)
堆可以任意任意顺序存⼊和移除(不按顺序)
抽象类 acstract
密封类 sealed
基类
派生类
protected