常见面试题目:

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

2. 结构和类的区别?

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

4. 堆和栈的区别?

5. 什么情况下会在堆(栈)上分配数据?它们有性能上的区别吗?

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

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

8. out 和 ref 的区别与相同点?

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

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

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

12. 如果结构体中定义引用类型,对象在内存中是如何存储的?例如下面结构体中的class类 User对象是存储在栈上,还是堆上?

public struct MyStruct
{
public int Index;
public User User;

认识值类型与引用类型

万变不离其宗,只要搞清楚值类型和引用类型的原理,上面所有题目就都迎刃而解了。

 基本概念

CLR支持两只类型:引用类型和值类型。这是.NET语言的基础和关键,他们从类型定义、实例创建、参数传递,到内存分配都有所不同。虽然看上去简单,但真正理解其内涵的人却好像并不多。

图片引用

下图清晰了展示了.NET中类型分类,值类型主要是一些简单的、基础的数据类型,引用类型主要用于更丰富的、复杂的、复合的数据类型。

 内存结构

值类型和引用类型最根源的区别就是其内存分配的差异,在这之前首先要理解CLR的内存中两个重要的概念:

Stack 栈:线程栈,由操作系统管理,存放值类型、引用类型变量(就是引用对象在托管堆上的地址)。栈是基于线程的,也就是说一个线程会包含一个线程栈,线程栈中的值类型在对象作用域结束后会被清理,效率很高。

GC Heap托管堆:进程初始化后在进程地址空间上划分的内存空间,存储.NET运行过程中的对象,所有的引用类型都分配在托管堆上,托管堆上分配的对象是由GC来管理和释放的。托管堆是基于进程的,当然托管堆内部还有其他更为复杂的结构,有兴趣的可以深入了解。

结合下图理解,变量a及其值3都是存储在栈上面。变量b在栈上存储,其值指向字符串“123”的托管堆对象地址(字符串是引用类型,字符串对象是存储在托管堆上面。字符串是一个特殊的引用类型,后面文章会专门探讨)”

值类型一直都存储在栈上面吗?所有的引用类型都存储在托管堆上面吗?

1.单独的值类型变量,如局部值类型变量都是存储在栈上面的;

2.当值类型是自定义class的一个字段、属性时,它随引用类型存储在托管堆上,此时她是引用类型的一部分;

4.所有的引用类型肯定都是存放在托管堆上的。

5.还有一种情况,同上面题目12,结构体(值类型)中定义引用类型字段,结构体是存储在栈上,其引用变量字段只存储内存地址,指向堆中的引用实例。

 对象的传递

将值类型的变量赋值给另一个变量(或者作为参数传递),会执行一次值复制。将引用类型的变量赋值给另一个引用类型的变量,它复制的值是引用对象的内存地址,因此赋值后就会多个变量指向同一个引用对象实例。理解这一点非常重要,下面代码测试验证一下:

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对象实例。

参数-按引用传递:

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

代码简单测试一下,如果换成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
}

out 和 ref的主要异同:

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

 常见问题

题目答案解析:

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

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

  • 1、赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对象的引用(即内存地址,类似C++中的指针),而不复制对象本身。
  • 2、继承:值类型不可能派生出新的类型,所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
  • 3、null:与引用类型不同,值类型不可能包含 null 值。然而,可空类型功能允许将 null 赋给值类型。
  • 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. out 和 ref的区别与相同点?

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

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

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

引用类型:Object,String

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

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

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

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

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

12. 如果结构体中定义引用类型,对象在内存中是如何存储的?例如下面结构体中的class类 User对象是存储在栈上,还是堆上?

public struct MyStruct
{
public int Index;
public User User;
}

MyStruct存储在栈中,其字段User的实例存储在堆中,MyStruct.User字段存储指向User对象的内存地址。

版权所有,文章来源:http://www.cnblogs.com/anding

个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。

.NET面试题2的更多相关文章

  1. .NET面试题系列[8] - 泛型

    “可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...

  2. 关于面试题 Array.indexof() 方法的实现及思考

    这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...

  3. 对Thoughtworks的有趣笔试题实践

    记得2014年在网上看到Thoughtworks的一道笔试题,当时觉得挺有意思,但是没动手去写.这几天又在网上看到了,于是我抽了一点时间写了下,我把程序运行的结果跟网上的答案对了一下,应该是对的,但是 ...

  4. 从阿里巴巴笔试题看Java加载顺序

    一.阿里巴巴笔试题: public class T implements Cloneable { public static int k = 0; public static T t1 = new T ...

  5. JAVA面试题

    在这里我将收录我面试过程中遇到的一些好玩的面试题目 第一个面试题:ABC问题,有三个线程,工作的内容分别是打印出"A""B""C",需要做的 ...

  6. C++常考面试题汇总

    c++面试题 一 用简洁的语言描述 c++ 在 c 语言的基础上开发的一种面向对象编程的语言: 应用广泛: 支持多种编程范式,面向对象编程,泛型编程,和过程化编程:广泛应用于系统开发,引擎开发:支持类 ...

  7. .NET面试题系列[4] - C# 基础知识(2)

    2 类型转换 面试出现频率:主要考察装箱和拆箱.对于有笔试题的场合也可能会考一些基本的类型转换是否合法. 重要程度:10/10 CLR最重要的特性之一就是类型安全性.在运行时,CLR总是知道一个对象是 ...

  8. 我们公司的ASP.NET 笔试题,你觉得难度如何

    本套试题共8个题,主要考察C#面向对象基础,SQL和ASP.NET MVC基础知识. 第1-3题会使用到一个枚举类,其定义如下: public enum QuestionType { Text = , ...

  9. 我设计的ASP.NET笔试题,你会多少呢

    本笔试题考查范围包括面向对象基础.HTML.CSS.JS.EF.jQuery.SQL.编码思想.算法等范围. 第1题:接口和抽象类有何区别? 第2题:静态方法和实例方法有何区别? 第3题:什么是多态? ...

  10. 猫哥网络编程系列:详解 BAT 面试题

    从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...

随机推荐

  1. Win10每次开机总是自动弹出MSN网址导航如何取消

    Win10每次开机总是自动弹出MSN网址导航如何取消 近来有用户在升级Win10系统后,每次开机总是会自动弹出MSN中文网的网址导航.如果不想要开机打开MSN网址导航,那么应该怎么设置来取消呢?对此, ...

  2. [MOOC程序设计与算法二] 递归二

    1.表达式计算 输入为四则运算表达式,仅由整数.+.-.* ./ .(.) 组成,没有空格,要求求其值.假设运算符结果都是整数 ."/"结果也是整数 表达式也是递归的定义: 表达式 ...

  3. 拖放(Drag和Drop)--html5

    拖放,就是抓取一个对象后拖放到另一个位置.很常用的一个功能,在还没有html5的时候,我们实现这个功能,通常会用大量的js代码,再利用mousemove,mouseup等鼠标事件来实现,总的来说比较麻 ...

  4. 解读人:董鑫,Disease Development Is Accompanied by Changes in Bacterial Protein Abundance and Functions in a Refined Model of Dextran Sulfate Sodium (DSS)-Induced Colitis

    文章中文名:在葡聚糖硫酸钠(DSS)诱导下的结肠炎模型伴随着细菌蛋白质丰度和功能的改变 单位: 1 Helmholtz-Centre for Environmental Research - UFZ, ...

  5. Django 实现的分页类

    后台实现的一个分页类: from django.utils.safestring import mark_safe class Page: def __init__(self, current_pag ...

  6. 解读人:林山云,Proteomic Identification of Protein Glutathionylation in Cardiomyocytes(心肌细胞蛋白质谷胱甘肽修饰的蛋白质组鉴定)

    发表时间:(2019年4月) IF:3.950 单位:韦恩州立大学化学系 物种:小鼠心肌细胞 技术:谷胱甘肽修饰蛋白组学 一. 概述: 本研究采用化学选择性蛋白组学方法,鉴定出过氧化物诱导HL-1小鼠 ...

  7. City Game UVALive - 3029(悬线法求最大子矩阵)

    题意:多组数据(国外题好像都这样),每次n*m矩形,F表示空地,R表示障碍 求最大子矩阵(悬线法模板) 把每个格子向上延伸的空格看做一条悬线 以le[i][j],re[i][j],up[i][j]分别 ...

  8. php字符串中去除html标签

    strip_tags() 函数剥去字符串中的 HTML.XML 以及 PHP 的标签.

  9. (转)Selenium-11: Execute JavaScript with JavascriptExecutor

    Outline Sometimes we cannot handle some conditions or problems with Webdriver, web controls don’t re ...

  10. Oulipo (KMP出现次数)

    The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e ...