分析.NETインタビュー質問(01) - 型の値型と参照

  一般的な面接の質問:

1.値型と参照型の違いは?

2.構造などの違いは?

3.デリゲートは、参照型または値型ですか?列挙型、int型[]と文字列のこと?

4.スタックとヒープの違いは?

データがどのような状況下でヒープ(スタック)5に割り当てられるのでしょうか?彼らは、パフォーマンスの違いがありますか?

6.「構造」は、ヒープ、それをオブジェクトに割り当てることができますか?どのような状況下では、それに注意を払う必要があるか、どうなりますか?

値によって渡される引数を理解して7?そして、参照渡し?

8. outref同じ点との差?

いくつかの定義済みの値の種類をサポートし9のC#?予め定められた基準の種類をサポートしていますC#の?

10.いくつかの方法決意値と参照型がありますが?

値型とライフサイクルの参照型約11の話?

12.構造参照型の定義は、メモリ内のオブジェクトがどのように記憶することですか?例えば、オブジェクトクラスUserクラスの以下の構造は、スタックまたはヒープに格納されていますか?

パブリック構造体体mystruct 
{ 
    公共のint型のインデックス。
    パブリックユーザーユーザー。

  値型と参照型の理解

原理的に明確な値型と参照型、上記解決されているすべての対象限り、同じままです。

スマイル 基本コンセプト

:CLRは、2種類のサポート参照型値型をこれは、基礎とキーの.NET言語であり、彼らは、型定義のインスタンスを作成し、パラメータはメモリ割り当てに渡されるが異なります。それは簡単なようだが、実際にはその意味を理解しますが、多くの人々が持っているようです。

画像の参照

明らかに、以下の図に示す分類の.NET型は、主型の値は、単純な、基本的なデータ型は、参照型は、主に、より豊かな、複雑で、複雑なデータ型のために使用されています。

笑い メモリアーキテクチャ

我々は最初の2つの重要な概念でCLRのメモリを理解する必要があります前に、メモリの割り当ては、値型と参照型のほとんどの原因との差の違いです:

スタックスタック:スレッドスタック、オペレーティング・システム管理、値型の参照型変数の格納(アドレスが管理ヒープ内のオブジェクトへの参照です)スタックは、スレッドのスタック値型は、対象範囲の終了時に洗浄されるスレッドは、スレッドのスタックを含むであろうことを意味し、効率が非常に高く、スレッドベースです。

GCヒープヒープ管理:初期化プロセスは、プロセスのアドレス空間のメモリ空間に分割された後に、.NETランタイムでオブジェクトを格納するプロセスは、すべての参照型は、マネージヒープ上に割り当てられ、管理ヒープ割り当てられたオブジェクトはGCによって管理されていますリリース。マネージドヒープはもちろん、そこに、他のマネージヒープより複雑な内部構造です理解することができます興味を持っている、プロセスベースです。

図3に関連して理解される、変数Aの値と3は、スタック上に格納されています。変数bが「123」のアドレス管理ヒープ・オブジェクト(文字列が参照型である文字列値を指し、スタック上に格納され、文字列が管理ヒープに格納され、上記オブジェクト。参照文字列が記事の後半、意志具体特殊タイプでありますディスカッション)」

画像

値型は、その上にスタック上に保存されていますか?すべての参照型は、その上にマネージヒープに格納されていますか?

そのようなローカル変数値のタイプとして可変型の1個々の値は、スタック上に格納されています。

2種類の値は、カスタムクラスフィールドの属性である場合には、彼女が参照型の一部である場合、マネージヒープの種類を参照して保存されています。

4.すべての参照型は、確かにマネージヒープに格納されています。

別の場合には5は、12以上の有する対象は、構造は、ヒープの参考例を指し、スタック、参照変数のフィールドのみを格納するメモリアドレスに格納され、構造の参照タイプフィールド(Type値)を定義します。

ウィンク オブジェクトを渡します

別の変数に値型の変数を割り当てる(またはパラメータとして渡された)、複製値を行います。参照型の別の変数への参照型の変数、そのコピーオブジェクトを参照するメモリアドレスの値、したがって同じオブジェクト・インスタンス可変基準点の複数後割り当てられることになります。テストをテストするには、次のコードを理解することが重要です。

int v1 = 0;
            int v2 = v1;
            v2 = 100;
            Console.WriteLine("v1=" + v1); //输出:v1=0
            Console.WriteLine("v2=" + v2); //输出:v2=100

            User u1=new User();
            u1.Age = 0;
            User u2 = u1;
            u2.Age = 100;
            Console.WriteLine("u1.Age=" + u1.Age); //输出:u1.Age=100
            Console.WriteLine("u2.Age=" + u2.Age); //输出:u2.Age=100,因为u1/u2指向同一个对象

当把对象作为参数传递的时候,效果同上面一样,他们都称为按值传递,但因为值类型和引用类型的区别,导致其产生的效果也不同。

参数-按值传递:

private void DoTest(int a)
        {
            a *= 2;
        }

        private void DoUserTest(User user)
        {
            user.Age *= 2;
        }

        [NUnit.Framework.Test]
        public void DoParaTest()
        {
            int a = 10;
            DoTest(a);
            Console.WriteLine("a=" + a); //输出:a=10
            User user = new User();
            user.Age = 10;
            DoUserTest(user);
            Console.WriteLine("user.Age=" + user.Age); //输出:user.Age=20
        }

上面的代码示例,两个方法的参数,都是按值传递

  • 对于值类型(int a) :传递的是变量a的值拷贝副本,因此原本的a值并没有改变。
  • 对于引用类型(User user) :传递的是变量user的引用地址(User对象实例的内存地址)拷贝副本,因此他们操作都是同一个User对象实例。

参数-按引用传递:

按引用传递的两个主要关键字:outref不管值类型还是引用类型,按引用传递的效果是一样的,都不传递值副本,而是引用的引用(类似c++的指针的指针)。outref告诉编译器方法传递额是参数地址,而不是参数本身,理解这一点很重要。

代码简单测试一下,如果换成out效果是相同的

private void DoTest( ref int a)
        {
            a *= 2;
        }

        private void DoUserTest(ref User user)
        {
            user.Age *= 2;
        }

        [NUnit.Framework.Test]
        public void DoParaTest()
        {
            int a = 10;
            DoTest(ref a);
            Console.WriteLine("a=" + a); //输出:a=20 ,a的值改变了
            User user = new User();
            user.Age = 10;
            DoUserTest(ref user);
            Console.WriteLine("user.Age=" + user.Age); //输出:user.Age=20
        }

outref的主要异同

  • outref都指示编译器传递参数地址,在行为上是相同的;
  • 他们的使用机制稍有不同,ref要求参数在使用之前要显式初始化,out要在方法内部初始化;
  • outref不可以重载,就是不能定义Method(ref int a)和Method(out int a)这样的重载,从编译角度看,二者的实质是相同的,只是使用时有区别;

舌の笑顔 常见问题

  题目答案解析:

1. 值类型和引用类型的区别?

值类型包括简单类型、结构体类型和枚举类型,引用类型包括自定义类、数组、接口、委托等。

  • 1、赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对象的引用(即内存地址,类似C++中的指针),而不复制对象本身。
  • 2、继承:值类型不可能派生出新的类型,所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
  • 3、null:与引用类型不同,值类型不可能包含 null 值。然而,可空类型允许将 null 赋给值类型(他其实只是一种语法形式,在clr底层做了特殊处理)。
  • 4、每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值,值类型初始会默认为0,引用类型默认为null。
  • 5、值类型存储在栈中,引用类型存储在托管堆中。

2. 结构和类的区别?

结构体是值类型,类是引用类型,主要区别如题1。其他的区别:

  • 结构不支持无惨构造函数,不支持析构函数,并且不能有protected修饰;
  • 结构常用于数据存储,类class多用于行为;
  • class需要用new关键字实例化对象,struct可以不适用new关键字;
  • class可以为抽象类,struct不支持抽象;

3. delegate是引用类型还是值类型?enum、int[]和string呢?

enum枚举是值类型,其他都是引用类型。

4. 堆和栈的区别?

线程堆栈:简称栈 Stack
托管堆: 简称堆 Heap
  • 值类型大多分配在栈上,引用类型都分配在堆上;
  • 栈由操作系统管理,栈上的变量在其作用域完成后就被释放,效率较高,但空间有限。堆受CLR的GC控制;
  • 栈是基于线程的,每个线程都有自己的线程栈,初始大小为1M。堆是基于进程的,一个进程分配一个堆,堆的大小由GC根据运行情况动态控制;

6.“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?

结构是值类型,有两种情况会分配在对上面:

  • 结构作为class的一个字段或属性,会随class一起分配在堆上面;
  • 装箱后会在堆中存储,尽量避免值类型的装箱,值类型的拆箱和装箱都有性能损失,下一篇会重点关注;

7. 理解参数按值传递?以及按引用传递?

  • 按值传递:对于值类型传递的它的值拷贝副本,而引用类型传递的是引用变量的内存地址,他们还是指向的同一个对象。
  • 按引用传递:通过关键字out和ref传递参数的内存地址,值类型和引用类型的效果是相同的。

8. outref的区别与相同点?

  • outref都指示编译器传递参数地址,在行为上是相同的;
  • 他们的使用机制稍有不同,ref要求参数在使用之前要显式初始化,out要在方法内部初始化;
  • outref不可以重载,就是不能定义Method(ref int a)和Method(out int a)这样的重载,从编译角度看,二者的实质是相同的,只是使用时有区别;

9. C#支持哪几个预定义的值类型?C#支持哪些预定义的引用类型?

值类型:整数、浮点数、字符、bool和decimal

引用类型:Object,String

10. 有几种方法可以判定值类型和引用类型?

简单来说,继承自System.ValueType的是值类型,反之是引用类型。

11. 说说值类型和引用类型的生命周期?

值类型在作用域结束后释放。

引用类型由GC垃圾回收期回收。这个答案可能太简单了,更详细的答案在后面的文章会说到。

12.構造参照型の定義は、メモリ内のオブジェクトがどのように記憶することですか?例えば、オブジェクトクラスUserクラスの以下の構造は、スタックまたはヒープに格納されていますか?

パブリック構造体体mystruct 
{ 
    公共のint型のインデックス。
    パブリックユーザーユーザー。
}

ユーザー例ヒープフィールドに格納されているスタック上に格納された体mystruct、MyStruct.Userフィールド格納メモリアドレスは、ユーザーオブジェクトを指します。

おすすめ

転載: www.cnblogs.com/ljdong7/p/12014527.html