在类的使用过程中,既不需要很多方法,也不需要从类中继承,为了提升性能,可以使用结构体来替代类。
与类不同的是,结构体用struct 修饰;结构体中的实例字段不能自定义默认值,而类可以,编译器会隐式的给出结构体和类的默认构造函数,但是结构体的默认构造不能显示给出,不然编译器会报错,当类有自定义的构造函数时,默认构造会被隐藏,要想使用默认构造,必须显示给出;结构体的自定义构造函数必须初始化所有的实例字段和未初始化的属性,而类不必。下面通过例子介绍结构体与类的区分,如下所示:
public class AA
{
// 类中的字段可以自定义默认值,也可以只声明
public int a = 1;
// 只声明的字段
public int b;
public int D{get;}
// 默认构造方法
public AA()
{
}
// 自定义构造方法,可以不用初始化没有自定义默认值的字段和属性
public AA(int x)
{
}
}
public struct BB
{
// 实例字段,不能在声明的时候给出默认值
public int a;
// 静态字段,外界可以通过结构体名访问,可以自定义默认值,如果没给,系统默认值0。
public static int b = 10;
// 属性,有默认返回值
public int C{get{return 1;}}
// 属性,没有默认返回值
public int D{get;}
// 静态属性
public static int E{get;}
// 自定义的构造方法,必须初始化所有没有自定义默认值的字段和属性
public BB(int x)
{
a = 1;
D = x;
}
public void Test()
{
// 在结构体内部(类也可以)可以使用只声明没有自定义默认值的字段或属性,结果是该类型的默认值
int f = a;
f = D;
}
}
由于结构体是值类型,所以在声明的时候系统就已经为他分配栈上的内存了,而 new 运算符只是调用结构体的构造函数去初始化结构体中的字段和属性。此时可以给该结构体的实例字段赋值,但是在使用该字段的值(比如,赋值给其他变量,用作方法的参数)之前必须要进行初始化(1、调用构造函数 2、给该字段先赋值)。下面给出调用的示例:
public class Test
{
public Test()
{
// 声明一个 BB 结构体类型的变量 bb,这是一个局部变量,使用他的实例字段之前要初始化
BB bb;
// int c = bb.a; bb.a 没有初始化,这样会报错
bb.a = 1;
int c = bb.a;
}
}
public class Test1
{
// 声明一个 BB 结构体类型的变量 bb,系统会默认调用该结构体的默认构造函数进行初始化(相当于:BB bb = new BB())
BB bb;
public Test1()
{
//这样不会报错,bb 已经有默认初始化
int c = bb.a;
}
}
结构体与类的不同点总结:
1、结构体是值类型,存储在栈上,类是引用类型,存储在托管堆上,结构体在声明的时候就已经为其分配栈上的内存了,而类需要用 new为其分配堆上面的内存;
2、结构体是隐式密封的,不能用 sealed 和 abstract 修饰,结构体不能被继承,类可以被继承;
3、结构体中的实例字段只能声明,不能赋值,而类没有限制,结构体只声明没有用 new 进行初始化时,可以给他的实例字段赋值,而类不行;
4、结构体没有析构函数,结构体中的方法不能用 virtual 和 abstract 修饰,但是可以用 override 修饰,用来重写父类的方法;
5、结构体不能显示给出默认构造函数(无参数的构造),无论有没有自定义构造,默认构造都隐式存在,而类中有自定义构造函数时,默认构造会被隐藏,要想调用默认构造,必须显示给出默认构造。
6、结构体的自定义构造函数必须初始化所有的实例字段和没有初始化的非静态属性,类没有限制。