类:
类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存
类有构造和析构函数
类可以继承和被继承
结构:
结构是值类型在栈上分配(虽然栈的访问速度比较堆要快,但栈的资源有限放),结构的赋值将分配产生一个新的对象。
结构没有构造函数,但可以添加。结构没有析构函数
结构不可以继承自另一个结构或被继承,但和类一样可以继承自接口
结构体和类同样能够定义字段,方法和构造函数,都能实例化对象,这样看来结构体和类的功能好像是一样的了,但是他们在数据的存储上是不一样的(以下摘录):
C#结构体和类的区别问题:在C#编程语言中,类属于引用类型的数据类型,结构体属于值类型的数据类型,这两种数据类型的本质区别主要是各自指向的内存位置不同。传递类的时候,主要表现为是否同时改变了源对象。
C#结构体和类的区别技术要点:
◆类在传递的时候,传递的内容是位于托管内存中的位置,结构体在传递的时候,传递的内容是位于程序堆栈区的内容。当类的传递对象修改时,将同时修改源对象,而结构体的传递对象修改时,不会对源对象产生影响。
◆在一个类中,可以定义默认的、不带参数的构造函数,而在结构体中不能定义默认的、不带参数的构造函数。两者都可以定义带有参数的构造函数,通过这些参数给各自的字段赋值或初始化
代码运行如下:类中赋值以后,两个对象中的值都发生变化,而结构体原来对象的值为发生变化
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 类对象 { //枚举 public enum Gender { 男, 女 } //结构体 public struct stuPerson { public string stuName; public int stuAge; public Gender stuSex; public void stuSayHello() { Console.WriteLine("我是{0},年龄{1},性别{2}", stuName, stuAge, stuSex); } //必须定义有参数的构造函数 public stuPerson(string name, int age, Gender sex) { this.stuName = name; this.stuAge = age; this.stuSex = sex; } } class Program { static void Main(string[] args) { //实例化类 Person Liuxiang = new Person(); //无参数的构造函数实例化的对象 Liuxiang.Name = "刘翔"; Liuxiang.Age = 30; Liuxiang.Sex = Gender.男; Liuxiang.SayHello(); //声明另一个实例 Person LXSon = Liuxiang; LXSon.Age = 10; //查看类 LiuXiang 和 LXSon中字段的值 Console.WriteLine("LiuXiang 年龄{0}", Liuxiang.Age.ToString()); //10 Console.WriteLine("LXSon 年龄{0}", LXSon.Age.ToString()); //10 Console.WriteLine(); //结构体 stuPerson YaoMing = new stuPerson("姚明",33,Gender.男); YaoMing.stuSayHello(); stuPerson YMSon = YaoMing; YMSon.stuAge = 13; //查看结构体中 YaoMing 和 YMSon中字段的值 Console.WriteLine("YaoMing 年龄{0}", YaoMing.stuAge.ToString()); //10 Console.WriteLine("YMSon 年龄{0}", YMSon.stuAge.ToString()); //10 Console.ReadLine(); } } class Person { //定义字段 public string Name; public int Age; public Gender Sex; //定义方法 public void SayHello() { Console.WriteLine("我是{0},年龄{1},性别{2}", this.Name, this.Age, this.Sex); } //无参数的构造函数 public Person() { } //有参数的构造函数 public Person(string name, int age, Gender sex) { this.Name = name; this.Age = age; this.Sex = sex; } } }
总结起来,两者共有如下区别:
1、结构是值类型,类则是引用类型。因此前者是放在栈(Stack)里,后者则仅仅是将引用地址存放在栈里,而具体的值则存放在堆(heap)里。如下图所示:
2、据第1点可以得出结论,那就是类对象通常用来传递大数据,而结构对象则用来传递小数据。
3、类可以被继承,而结构则不支持。
4、结构对象不能像类对象一样赋值为null。
5、结构不能像类一样定义析构器。
6、结构不能像类一样定义为抽象的。
7、在结构中不能重写方法,除非是object类型的如下方法:
- Equals()
- GetHashCode()
- GetType()
- ToString()
若要让结构具有多态特性,可以让其实现接口。
8、在类中定义的事件是线程安全的,而结构则不是。
9、结构总是具有一个默认的公共无参构造函数,但去不能像类一样定义私有的无参构造函数:
struct Me { private Me() // compile-time error { } } class Me { private Me() // runs Ok{ }
10、类中的静态构造函数会被调用,而结构却不能。因此在结构中定义的静态构造函数,虽然可以编译通过,但却没有价值:
struct myStructure { static myStructure() { Console.WriteLine("This is me a structure"); } } class myClass { static myClass() { Console.WriteLine("This is me a class"); } } class Program { static void Main(string[] args) { myStructure s = new myStructure();//Nothing happen myClass c = new myClass();//Will out put This is me a class Console.Read(); } }
11、结构不能像类一样定义volatile字段。volatile字段主要用于并发,它相当于方法体的lock。
12、可以对结构类型使用sizeof,对类则不行。
13、类的字段会被自动初始化为0/false/null,而结构则不能。
14、在结构中不能直接对字段初始化,而类则可以。
struct myStructure { public string x = 2;//Not allowed } class myClass { public string x = 2; //Allowed }
15、结构和类对于System.Object.Equals()方法的体现是不相同的。例如定义这样的结构和类:
struct StructurePerson { public string FirstName; public string LastName; } class ClassPerson { public string FirstName; public string LastName; }
如果运行如下的代码:
class Program { static void Main(string[] args) { StructurePerson strX = new StructurePerson(); strX.LastName = "Bejaoui"; strX.FirstName = "Bechir"; StructurePerson strY = new StructurePerson(); strY.LastName = "Bejaoui"; strY.FirstName = "Bechir"; if (strX.Equals(strY)) { Console.WriteLine("strX = strY"); } else { Console.WriteLine("strX != strY"); }//This code displays strX = strY ClassPerson clsX = new ClassPerson(); clsX.LastName = "Bejaoui"; clsX.FirstName = "Bechir"; ClassPerson clsY = new ClassPerson(); clsY.LastName = "Bejaoui"; clsY.FirstName = "Bechir"; if (clsX.Equals(clsY)) { Console.WriteLine("clsX = clsY"); } else { Console.WriteLine("clsX != clsY"); }//This code displays clsX != clsY Console.Read(); } }
ClassPerson clsX = new ClassPerson(); clsX.LastName = "Bejaoui"; clsX.FirstName = "Bechir"; ClassPerson clsY = clsX; if (clsX.Equals(clsY)) { Console.WriteLine("clsX = clsY"); } else { Console.WriteLine("clsX != clsY"); }//This codedisplays clsX = clsY
由于是直接将clsX赋值给clsY,因此两个对象的引用地址相等,Equals()方法返回true。
其实对于值类型和引用类型的相等性比较,是一个比较复杂的问题。例如我们可以通过重写Equals()方法增强或修改比较逻辑。重写Equals()方法还必须重写GetHashCode()方法。对于引用类型,还可以使用静态方法ReferenceEquals()方法。此外,还可以重载操作符==。另外,对于String对象,则比较特殊,因为它使用了Immutable模式。虽然String类型是引用类型,但如果直接定义的两个String对象的值相同,由于采用了Immutable模式的原因,这两个对象其实是同一个对象,引用地址是相同的。因此不仅动态方法Equals()返回的是true,且静态方法ReferenceEquals()返回的也是true