对C#中用new关键字实例化对象的理解 您所在的位置:网站首页 new是什么关键字 对C#中用new关键字实例化对象的理解

对C#中用new关键字实例化对象的理解

2023-10-24 11:38| 来源: 网络整理| 查看: 265

【前置知识】

对值类型和引用类型的理解

公共语言运行时CLR

对C#数组声明方式的理解

【实例化格式】

类名  对象名 = new 类名 (参数列表)

【相关概念辨析】

类是模板,定义了对象在实例化的时候看起来像什么样子。

对象是类的一个实际的例子,简称实例。

实例化是从类创建对象的过程。

举例而言:类可以看做是图纸,我们根据这个图纸做出来一个东西(即对象),做出来的东西就是图纸的实例,做这个东西的过程将类实例化了。

【实例化的过程】

以MyClass  myClass = new MyClass()为例:

MyClass是自定义的类(即自己写的一个类),myClass是要创建的对象名(即实例化的对象)。

new关键字的作用是让CLR为对象分配内存并返回引用(即new关键字告诉CLR我这边要创建一个对象,你那边要在堆中找块地方存储创建这个对象所需要的数据,创建好了之后再告诉我你是在堆中哪个位置创建的)。

(注解:实例化对象时需要初始的数据,正如我们声明数组时要给初始值一样,而且这些数据需要有专门的地方来存储。另外,存储之后还需要知道在哪存储的,要不然等需要用这些数据的时候不知道在哪找。)

所以,new MyClass()会返回引用,通过“=”操作符将引用赋值给myClass,而myClass本身可能在栈中,也可能在堆中,无论myClass在哪,其中存储的都是引用,而不是数据本身。

末尾的()表示用 MyClass这个类的构造器对myClass这个对象进行初始化,即构造器决定了创建这个对象时需要哪些初始数据。

【拓展】

在声明实例化数组时,其格式跟我们声明自定义的类是一样的,如

int[] A = new int[3];

int[] 可以看做是一个类,C#内置的、预定义的类。同样的,int、string 、float也可以看做是类,以下声明的方式都是可以的。

int x = new int();//给了初始值0 x = 3;//自己赋值 float y=new float();//给了初始值0.0 y=3.0f;//自己赋值

另一方面,int、float本身也是基础的数据类型,其作为类时使得自然界中的数据得以在计算机中表示。

【CLR如何响应new】

如上文所说,new关键字的作用是让CLR为对象分配内存并返回引用。

CLR在哪分配内存呢?

        在进程初始化时,CLR划出一个地址空间区域作为托管堆,也即存储用new来生成的对象的位置。同时,CLR会维护一个指针,称为NextObjPtr,这个指针指向了下一个对象在堆中的分配位置。在未生成任何对象时,NextObjPtr是托管堆的基地址(堆的地址由低到高,也就是最低的那个地址)。每生成一个对象之后,都把NextObjPtr指针移动到下一个空闲位置。这样,通过这个指针,就知道了在哪分配内存。

CLR分配多少内存呢?

        我们只有知道分配多少内存之后,才知道要把NextObjPtr上移多少后会指向下一个空闲位置。

        首先CLR会计算类型的实例字段所需的字节数。这里的类型指什么?引用类型,包括类、接口、委托等。以最常见的类为例,类中的字段是这个类的实例所能拥有的全部数据,对这些数据有的必须要有一个初值,你就需要在构造器中初始化。对类中的int、float等常见的类型,你肯定知道要多少字节。对int[]数组呢?例如private int[] a; 这也是一个字段,a存储的是引用,引用的大小也是知道的,没有实例化的时候其值为null,就像没有给int b赋值时b的值为0一样。如果通过private int[] a=new int[3]实例化了,只不过类中的字段a有了值而已,这个值是实例化一个int类型数组时CLR为其分配的内存的位置(即引用)。如果你在构造函数中完成数组的实例化,这意味着实例化了两个对象,一个是当前类型的对象,一个是数组对象。而类中的方法在实例化时并不会占用空间,只会在调用这个方法时才会开辟空间。对方法中的临时变量,值类型的就存储在栈中,引用类型的就要重新开辟空间。特殊的,对于继承,还要算上从父类继承的字段所需的字节数。所以说,对于一个类本身来说,其所占的内存并不会很大,但这个类中字段(或者说变量)所引用的全部对象合起来所占用的内存可能会很大。

        其次,每个对象生成时,还需要存储类型对象指针和同步块索引。类型对象指针就是这个对象的引用,同步块索引主要是为了在lock线程时确保线程同步。在32位程序中,两者共需要8字节;在64为程序中,两者共需要16字节。

        最后,CLR会检查剩余空间是否大于对象生成所需空间。如果大于,那么就在NextObjPtr所指的位置放入对象,调用类型(即对象对应的类)构造器初始化数据,new操作符返回对象的引用。返回引用前,NextObjPtr指针的值加上对象所占用的字节数得到新的值,也即下一个对象放入托管堆时的位置。

 

【参考】

《C#本质论5.0》

《CLR via C#》

【相关链接】

对C#构造器的理解



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有