前言
值类型与引用类型的区别,是我们学习面向对象语言必须掌握的重要知识点。
迅速回顾
值类型
值类型变量直接存储数据,其数据存储在栈内存中。在栈内存中存储的是值类型的数据,而不是地址。
主要的值类型,也被称为基本数据类型,有:byte,short,int,long,double,float,char,bool(java 中是 boolean ,c语言无),char,以及 struct (结构体),枚举 。
值类型的变量声明后,编译器会为其分配内存,无论是否赋值。
引用类型
引用类型由类型的实际值引用(类似于指针)表示的数据类型。引用类型也是一个数据类型,其相当于指针指向一个堆地址。
当引用类型实例化时,这些数据会在堆内存中分配空间,然后会由栈内存中在引用类型声明时预留的地址空间获取到堆内存中的空间地址。(也即是,栈内存中存储这引用类型在堆内存中的空间地址)
一般引用类型有:String ,Class等。
引用类型声明时,只会在栈内存中开辟一个地址大小的空间。只有当进行实例化分配堆内存空间时(比如 new),栈内存中会存储堆内存的相应地址。
比较
相同点
- 引用类型可实现接口,值类型的结构体也可以实现接口。
- 都是 System.Object 的子类(值类型继承自 System.ValueType ,而 ValueType 继承自 Object)
不同点
- 值类型分配在堆栈上,引用类型在堆上分配。如果一个引用类型某个成员变量是值类型,则此属性是分配在堆上的。 (局部变量一般在*栈*中被分配)
- 所有值类型都是隐式密封的(sealed),值类型不可派生,不可继承。
- 值类型每次赋值都会执行一次逐字段的复制,而引用类型赋值只是指针的传递,其实也是生成新的指针实例。这方面引用类型的性能较好。
- 值类型的之间赋值,数据会 copy ,引用类型只是指针的变化。
- 值类型不由 GC 来回收,作用域结束后会自行释放。而引用类型要由 GC 来回收,因此这里值类型的性能较好。
- 值类型变量不可为 null ,默认赋值为0;引用类型可以。
- 值类型有两种状态:装箱和未装箱;引用类型通常只有一种形式:装箱。
使用场景
- 值类型不会派生其他类型,也就是不可被继承。
- 值类型往往适合用作存储数据的载体;引用类型可以用于定义应用程序的行为。
C# 中结构体与类的区别
c# 中 结构体与类的用法区别不大。
c# 的结构体内部成员可为空,也可设置 public 和 private 以及可以定义方法。几乎和类的用法一样。
区别在于:
- 结构体是值类型,类是引用类型。即使结构体可以使用 new ,但依旧在栈区中。
- 结构体不支持继承。
- 结构体不能声明默认的构造函数。(但可以写带参构造函数)
结构体中
1 | struct PR{ |
使用 new 与不使用的区别在于,new 会进行默认赋值的初始化。而不使用 new 其第二句pr_2.a
是会报错,提示没有进行初始化赋值。