静态类
使用static修饰的类即为静态类
1.由于静态类是使用static修饰的所有类的内存在编译阶段就已经分配好了一份且是唯一的一份,
所以静态类是不允许创建实例的,因此在静态类中的所有成员都必须是静态的,但是在普通类中我们可以使用static来修饰一个函数即静态函数,那么我们可以使用static修饰一个普通类的构造函数吗?答案是肯定的,使用static修饰一个普通类的构造函数是C#中特有的,静态构造函数不能带有参数与访问权限修饰符,同时一个类只能有一个静态构造函数,并且不能被显式的调用
2.静态类的内存存放在静态全局区,静态全局区的内存是在整个程序结束时释放的,如果我们使用一个类来继承一个静态类,那么派生类被释放时会调用基类的析构函数,则会提前释放静态的内存,这种情况是不被允许的,因此静态类不能被继承
3.静态类中的构造函数不能使用方向权限符修饰也不能有参数
static class C
{
static int num; //成员必须为静态
static C() //不能添加访问权限修饰符 与参数否则报错
{
}
public static void Test()
{
Console.WriteLine("Test");
}
}
//class D:C 静态类不能被继承
// {
//}
class D
{
public int num;
static D()
{
}
}
static void Main(string[] args)
{
C.Test(); //通过类名.成员 来访问成员
//C c=new C(); 报错 静态类不能实例化对象
//D.D()不能显式调用静态构造
}
抽象类(abstract)与密封类(sealed)
与抽象类相比,密封类不能被其他类继承,但是可以继承其他类
同时密封类中可以定义密封方法即用sealed修饰的方法 (能被sealed修饰的方法必须是重写基类的virtual/abstract方法)
因为密封类不能被继承,使用抽象类不能定义为密封类,密封类也不能定义为抽象类
abstract class A
{
public abstract void Test(); //使用abstract修饰的函数只需要声明不需要函数体
}
sealed class B : A
{
public override void Test()
{
Console.WriteLine("override Test");
}
}
// class F : B { } 错误提示:无法重密封类中派生
class F:A
{
public sealed override void Test() //只能使用sealed 修饰override函数
{
Console.WriteLine("sealed Test");
}
}
class E:F
{
public override void Test() { } //错误提示:Test是密封的不能被重写
}
static void Main(string[] args)
{
}
抽象类与接口(interface)
接口:
1.接口定义了属性、方法和事件,接口中只有成员声明,成员定义定义有派生类来实现。
2.在接口中的成员不能有访问权限修饰符
3.接口不能直接创建实例,但是可以间接创建实例(与抽象类相似)
4.继承接口的类必须实现接口中的所有成员,如果一个类继承了多个接口,那么这个类需要实现这些接口的所有成员
接口与抽象类对比
相同点:
都不能直接实例化
都可以被继承,且派生类中必须实现接口/抽象类中为实现的成员
抽象类中的抽象函数与接口的成员只声明,由派生类实现
不同点:
抽象类中可以定义字段,属性,方法,而接口不能定义字段。
一个类只有一个基类,但可以继承多个接口
接口中的功能应该专一,而不是多功能,否则会造成接口的污染
class Program
{
interface TestInterface
{
//int a; 错误接口中不能包含字段
int Id { get; set; } //提供属性声明
void Test(); //提供方法声明
}
class Test01 : TestInterface
{
private int _id;
public int Id { get { return _id; } set { _id = value; } } //实现接口中Id属性
public void Test()
{
Console.WriteLine("interface test{0}",_id);
}
}
static void Main(string[] args)
{
// TestInerface ife= new TestInterface //错误 接口不能实例化
Test01 t1 = new Test01();
t1.Id = 1;
t1.Test();
}
}
字符串(stringbuilder)
stringbuilder内部实现与动态数组类似,工作原理是想申请一段大小为size的内存,当一个stringbuilder变量所需存储的内容空间大于size时 会自动申请size*2大小的内存重新赋给stringbuilder变量。
少量字符串操作,且字符串不经常发生变化时,优先使用stirng
static void Main(string[] args)
{
StringBuilder s1 = new StringBuilder("12346");
Console.WriteLine(s1.Capacity); //内存空间大小为16
Console.WriteLine(s1.Length); //长度为5
s1.Append("asdsadsadasddsdsd"); //内存16不够使用size*2
Console.WriteLine(s1.Capacity);//内存空间大小32
Console.WriteLine(s1.Length); // 长度为22
}