NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱
- 格式:doc
- 大小:588.00 KB
- 文档页数:8
面向对象面试题1、什么是面向对象面向对象OO = 面向对象的分析OOA + 面向对象的设计OOD + 面向对象的编程OOP;通俗的解释就是万物皆对象,把所有的事物都看作一个个可以独立的对象(单元),它们可以自己完成自己的功能,而不是像C那样分成一个个函数;现在纯正的OO语言主要是java和C#,C++也支持OO,C是面向过程的。
2、简述private、protected、public、internal 修饰符的访问权限。
private : 私有成员, 在类的内部才可以访问。
protected : 保护成员,该类内部和继承类中可以访问。
public : 公共成员,完全公开,没有访问限制。
internal: 当前程序集内可以访问。
3、中的五个主要对象Connection:主要是开启程序和数据库之间的连结。
没有利用连结对象将数据库打开,是无法从数据库中取得数据的。
这个物件在 的最底层,我们可以自己产生这个对象,或是由其它的对象自动产生。
Command:主要可以用来对数据库发出一些指令,例如可以对数据库下达查询、新增、修改、删除数据等指令,以及呼叫存在数据库中的预存程序等。
这个对象是架构在Connection 对象上,也就是Command 对象是透过连结到数据源。
DataAdapter:主要是在数据源以及DataSet 之间执行数据传输的工作,它可以透过Comm and 对象下达命令后,并将取得的数据放入DataSet 对象中。
这个对象是架构在Command 对象上,并提供了许多配合DataSet 使用的功能。
DataSet:这个对象可以视为一个暂存区(Cache),可以把从数据库中所查询到的数据保留起来,甚至可以将整个数据库显示出来。
DataSet 的能力不只是可以储存多个Table 而已,还可以透过DataAdapter对象取得一些例如主键等的数据表结构,并可以记录数据表间的关联。
DataSet 对象可以说是 中重量级的对象,这个对象架构在DataAdapter对象上,本身不具备和数据源沟通的能力;也就是说我们是将DataAdapter对象当做DataSet 对象以及数据源间传输数据的桥梁。
本文档是学习《C#高级编程》第七版的读书笔记,对于一些资源参考了网络相关文章。
本文档仅供个人学习,不可用于商业行为。
第Ⅰ部分部分 C#C#语言语言语言第一章第一章 .NET 体系结构1. 什么是 .NET Framework?2. C#语言和 .NET Framework 关系是什么?3. 什么是公共语言运行库?4. 什么是托管代码? 其与非托管代码有什么不同? 他们执行效率如何?5. IL 是什么?6. 什么是程序集?7. 值类型和引用类型的区别?答1:.NET Framework 是用于Windows 的新托管代码编程模型。
.NET Framework 又称 .Net 框架。
一个致力于敏捷软件开发(Agile software development Agile software developmentAgile software development)、快速应用开发(Rapid Rapid application developmentapplication development)、平台无关性和网络透明化的软件开发平台。
.NET 框架是以一种采用系统虚拟机运行的编程平台,以通用语言运行库(Common Language Runtime Common Language Runtime Common Language Runtime)为基础,支持多种语言(C#、VB、C++、Python 等)的开发。
答2:C#本身只是一种语言,尽管它是用于生成面向.NET 环境的代码,但它本身不是.net 的一部分。
.net 支持的一些特性,C#并不支持。
而C#语言支持的另一些特性,.net 却不支持。
但C#语言是和.NET 一起使用的,所以如果要使用C#高效地开发应用程序,理解Framework 就非常重要。
答3:.NET Framework 的核心是其运行库的执行环境, 称为公共语言运行库公共语言运行库 (CLR) 或 .NET 运行库。
第1部分 .NET基本概念1.应用程序域:应用程序域可以理解为一种轻量级进程。
起到安全的作用。
占用资源小。
应用程序域提供安全而通用的处理单元,公共语言运行库可使用它来提供应用程序之间的隔离。
开发者可以在具有同等隔离级别(存在于单独的进程中)的单个进程中运行几个应用程序域,而不会造成进程间调用或进程间切换等方面的额外开销。
在一个进程内运行多个应用程序的能力显著增强了服务器的可伸缩性。
2.CTS:通用类型系统。
CTS:类似于COM定义的标准二进制格式,.NET定义了一个称为通用类型系统 Common Type System (CTS)的类型标准。
这个类型不但实现COM的变量兼容,而且还定义了通过用户自定义类型的方式进行类型扩展。
任何类型的方式进行类型扩展。
任何以.NET平台作为目标的语言必须建立它的数据类型与CTS的类型间的影射。
所有.NET语言共享这一类型系统,实现他们之间无缝的互操作。
该方案还提供了语言之间的继承性。
3.CLS:公共语言规范。
.NET通过定义公共语言规范(CLS:Common Language Specification),限制了由这些不同引发的互操作性问题。
CLS指定了一种以.NET平台为目标的语言所必须支持的最小特征,以及该语言与其他.NET语言之间实现互操作性所需要的完备特征。
CLS是CTS的一个子集。
4.CLR:公共语言运行库Common Language Runtime(CLR).CLR是CTS的实现,也就是说,CLR是应用程序的执行引擎和功能齐全的类库,该类库严格按照CTS规范实现。
作为程序执行引擎,CLR负责安全地载入和运行用户程序代码,包括对不同对象的垃圾挥手和安全检查。
CLR监控之下运行的代码,称为托管代码(managed code)。
5.IL(Intermediate Language,中间语言):可用于语言互操作性,IL不是字节代码,但很接近字节代码,因此执行应用程序时,IL到机器代码的转换要快很多。
Unity面试题(含答案)史上最全的Unity面试题(持续更新总结。
)包含答案的Unity面试题这个是我刚刚整理出的Unity面试题,为了帮助大家面试,同时帮助大家更好地复习Unity知识点,如果大家发现有什么错误,(包括错别字和知识点),或者发现哪里描述的不清晰,请在下面留言,我会重新更新,希望大家共同来帮助开发者一:什么是协同程序?在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行,协程很像多线程,但是不是多线程,Unity的协程实在每帧结束之后去检测yield的条件是否满足。
二:Unity3d中的碰撞器和触发器的区别?碰撞器是触发器的载体,而触发器只是碰撞器身上的一个属性。
当Is Trigger=false时,碰撞器根据物理引擎引发碰撞,产生碰撞的效果,可以调用OnCollisionEnter/Stay/Exit函数;当Is Trigger=true时,碰撞器被物理引擎所忽略,没有碰撞效果,可以调用OnTriggerEnter/Stay/Exit函数。
如果既要检测到物体的接触又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中的某个区域这时就可以用到触发器三:物体发生碰撞的必要条件?两个物体都必须带有碰撞器(Collider),其中一个物体还必须带有Rigidbody刚体,而且必须是运动的物体带有Rigidbody脚本才能检测到碰撞。
四:请简述ArrayList和List的主要区别?####ArrayList存在不安全类型(ArrayList会把所有插入其中的数据都当做Object来处理)?装箱拆箱的操作(费时)?List是接口,ArrayList是一个实现了该接口的类,可以被实例化五:如何安全的在不同工程间安全地迁移asset数据?三种方法1.将Assets目录和Library目录一起迁移2.导出包,export Package3.用unity自带的assets Server功能六:OnEnable、Awake、Start运行时的发生顺序?哪些可能在同一个对象周期中反复的发生Awake –>OnEnable->Start,OnEnable在同一周期中可以反复地发生。
装箱跟拆箱的概念
装箱和拆箱是两个在计算机科学中常用的术语,主要用于描述将数据从一种类型转换为另一种类型的操作。
装箱(boxing)是指将一个值类型(如整数、浮点数、字符等)封装为对应的引用类型(如整数类、浮点数类、字符类等)的过程。
在Java中,装箱通常是由编译器自动完成的,例如将int类型的整数自动装箱为Integer类型的对象。
装箱的过程会对原始数据进行封装,使其具有更多的功能,但也会引入一定的性能开销。
拆箱(unboxing)是指将一个引用类型(如包装类对象)解包为对应的值类型(如基本数据类型)的过程。
在Java中,拆箱通常也是由编译器自动完成的,例如将Integer类型的对象自动拆箱为int类型的整数。
拆箱的过程会将引用类型的数据还原为原始的值类型,以便进行计算或其他操作。
装箱和拆箱的概念在Java中特别重要,因为一些集合类(如List、Set)只能存储引用类型的数据,而不能直接存储值类型的数据。
因此,在需要将值类型数据存储到集合类中时,编译器会自动进行装箱操作,将值类型数据封装成引用类型对象存储到集合中;在需要从集合中取出数据进行计算时,编译器会自动进行拆箱操作,将引用类型对象还原为原始值类型进行计算。
这使得值类型的数据可以和引用类型的数据一样方便地在集合类中进行操作。
拆箱概念1. 装箱和拆箱是一个抽象的概念。
2. 装箱是将值类型转换为引用类型;拆箱是将引用类型转换为值类型;利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型与引用类型链接起来。
例如:intval = 100;objectobj = val;Console.WriteLine (“对象的值= {0}", obj);这是一个装箱的过程,是将值类型转换为引用类型的过程。
intval = 100;objectobj = val;intnum = (int) obj;Console.WriteLine ("num: {0}", num);这是一个拆箱的过程,是将值类型转换为引用类型,再由引用类型转换为值类型的过程。
注:被装过箱的对象才能被拆箱3. .NET中,数据类型划分为值类型和引用(不等同于C++的指针)类型,与此对应,内存分配被分成了两种方式,一为栈,二为堆,注意:是托管堆。
值类型只会在栈中分配;引用类型分配内存与托管堆;托管堆对应于垃圾回收。
4. 装箱/拆箱是什么?装箱:用于在垃圾回收堆中存储值类型。
装箱是值类型到object 类型或到此值类型所实现的任何接口类型的隐式转换。
拆箱:从object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。
5. 为何需要装箱?(为何要将值类型转为引用类型?)一种最普通的场景是,调用一个含类型为Object的参数的方法,该Object可支持任意为型,以便通用。
当你需要将一个值类型(如Int32)传入时,需要装箱。
另一种用法是,一个非泛型的容器,同样是为了保证通用,而将元素类型定义为Object。
于是,要将值类型数据加入容器时,需要装箱。
6. 装箱/拆箱的内部操作。
装箱:对值类型在堆中分配一个对象实例,并将该值复制到新的对象中。
按三步进行。
第一步:新分配托管堆内存(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex)。
attribute翻译成特性,用来标识类,方法。
property翻译为属性,性质用于存取类的字段。
markup翻译成标记。
tag翻译成标签。
[.NET(C#)]程序集的一个重要特性是它们包含的元数据描述了对应代码中定义的类型和方法。
[.NET(C#)]ASP页面有时显示比较慢,因为服务器端代码是解释性的不是编译的。
页面是结构化的。
每个页面都是一个继承了.NET类System.Web.UI.Page的类。
[.NET(C#)]重写override:是指子类重新定义父类的虚函数的做法。
重载overload:是指允许存在多个同名函数,而函数签名不同(参数表不同:或许参数个数不同,或许参数类型不同,或许两者都不同)。
重载的概念并不属于“面向对象编程”。
[.NET(C#)]ref 关键字使参数按引用传递。
其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
out 关键字会导致参数通过引用来传递。
这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。
若要使用 out 参数,方法定义和调用方法都必须显式使用out 关键字。
[.NET(C#)]ADO和的区别:ADO使用OLE DB接口并基于微软的COM技术;而拥有自己的接口并且基于微软的.NET体系架构。
ADO以Recordset存储,而则以DataSet表示。
Recordset看起来更像单表,如果让Recordset以多表的方式表示就必须在SQL中进行多表连接。
反之,DataSet可以是多个表的集合。
ADO 的运作是一种在线方式,这意味着不论是浏览或更新数据都必须是实时的。
则使用离线方式,在访问数据的时候会利用XML制作数据的一份幅本的数据库连接也只有在这段时间需要在线。
[.NET(C#)]new 关键字用法:1)new 运算符:用于创建对象和调用构造函数。
尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(Garbage Collection),但是我们还是应该了解它们,以优化我们的应用程序。
同时,还需要具备一些基础的内存管理工作机制的知识,这样能够有助于解释我们日常程序编写中的变量的行为。
在本文中我将讲解栈和堆的基本知识,变量类型以及为什么一些变量能够按照它们自己的方式工作。
在.NET framework环境下,当我们的代码执行时,内存中尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(Garbage Collection),但是我们还是应该了解它们,以优化我们的应用程序。
同时,还需要具备一些基础的内存管理工作机制的知识,这样能够有助于解释我们日常程序编写中的变量的行为。
在本文中我将讲解栈和堆的基本知识,变量类型以及为什么一些变量能够按照它们自己的方式工作。
在.NET framework环境下,当我们的代码执行时,内存中有两个地方用来存储这些代码。
假如你不曾了解,那就让我来给你介绍栈(Stack)和堆(Heap)。
栈和堆都用来帮助我们运行代码的,它们驻留在机器内存中,且包含所有代码执行所需要的信息。
* 栈vs堆:有什么不同?栈负责保存我们的代码执行(或调用)路径,而堆则负责保存对象(或者说数据,接下来将谈到很多关于堆的问题)的路径。
可以将栈想象成一堆从顶向下堆叠的盒子。
当每调用一次方法时,我们将应用程序中所要发生的事情记录在栈顶的一个盒子中,而我们每次只能够使用栈顶的那个盒子。
当我们栈顶的盒子被使用完之后,或者说方法执行完毕之后,我们将抛开这个盒子然后继续使用栈顶上的新盒子。
堆的工作原理比较相似,但大多数时候堆用作保存信息而非保存执行路径,因此堆能够在任意时间被访问。
与栈相比堆没有任何访问限制,堆就像床上的旧衣服,我们并没有花时间去整理,那是因为可以随时找到一件我们需要的衣服,而栈就像储物柜里堆叠的鞋盒,我们只能从最顶层的盒子开始取,直到发现那只合适的。
C#基础语法——C#基本数据类型数据类型主要用于指明变量和常量存储值的类型,C# 语言是一种强类型语言,要求每个变量都必须指定数据类型。
数据类型分为值类型和引用类型两种存储类型:堆、栈。
两种存储释放内存的方式:栈(Stack):退出方法后按先进后出的方式释放,堆(Heap)由GC自动回收。
值类型:数据跟内存都保存在同一位置。
引用类型:引用类型则会有一个指向实际内存区域的指针。
装箱:值类型转引用类型。
拆箱:引用类型转值类型。
从内存存储空间的角度而言,值类型的值是存放到栈中的,每次存取值都会在该内存中操作;引用类型首先会在栈中创建一个引用变量,然后在堆中创建对象本身,再把这个对象所在内存的首地址赋给引用变量。
值类型:简单类型:有符号整型:sbyte、short、int,、long、无符号整型:byte、ushort、uint、ulong、char、float、double、decimal、bool枚举类型:enum结构类型:struct引用类型:类类型:object、string、class接口类型:interface数组类型:int[]、int[,]委托类型:delegate整型所谓整型就是存储整数的类型,按照存储值的范围不同,C# 语言将整型分成了byte 类型、short 类型、int 类型、long 类型等,并分别定义了有符号数和无符号数。
有符号数可以表示负数,无符号数仅能表示正数。
具体的整数类型及其表示范围如下表所示。
从上面的表中可以看出short、int 和long 类型所对应的无符号数类型都是在其类型名称前面加上了u 字符,只有byte 类型比较特殊,它存储一个无符号数,其对应的有符号数则是sbyte。
此外,在C# 语言中默认的整型是int 类型。
每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。
例如:int i = new int(); 等价于:Int32 i = new Int32();等价于:int i = 0;等价于:Int32 i = 0;引用类型和值类型都继承自System.Object类。
6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
引言
本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱。
文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆;最后介绍值类型和引用类型,并说明一些有关它们的重要原理。
最后通过一个简单的示例代码说明装箱拆箱带来的性能损耗。
声明变量的内部机制
在.NET程序中,当你声明一个变量,将在内存中分配一块内存。
这块内存分为三部分:1,变量名;2,变量类型;3,变量值。
下图揭示了声明一个变量时的内部机制,其中分配的内存类型依据你的变量类型。
.NET中有两种类型的内存:栈Stack内存和堆Heap内存。
在接下来的内容中,我们会了解到这两种类型的详细内容。
栈和堆
为了明白什么是栈和堆,先让我们看下下面示例代码的内部机制:
?
这里一共有3行代码。
让我们一下逐行看一下它们是如何执行的:
第1行:当这行代码执行时,编译器为它分配一小块栈内存。
运行时栈负责提供程序所需的内存;第2行:程序继续执行。
如同名字一样,栈在第一块内存的顶部分配了一块内存。
你也可以认为是模块或零件一块一块叠起来;
内存的分配与释放遵循后进先出(后进先出)逻辑,换句话说,内存只能在示例中i内存块的顶部分配或释放。
第3行:在第3行,我们创建了一个对象。
当该行执行时,编译器在站上创建了一个指针,真实的对象存储在另一种叫“堆”的内存中。
"堆"并不跟踪运行内存,它更像一堆随时可以访问的对象。
堆用于动态分配内存。
这里需要着重说明的是引用指针是分配在栈上。
声明Class1 cls1时并不会给Class1的实例分配内存,而是分配一个栈变量cls1(并设置为null),然后把它指向“堆”。
退出方法:当方法退出时,它释放了栈上所有内存变量。
换句话说,栈上所有的"Int"变量都依据后进先出的逻辑被释放掉了。
要注意,此时不会释放堆内存,这种内存稍后会被“垃圾收集器”释
放。
现在可能会有很多朋友奇怪为什么要分配2种内存,而不是仅用一种内存。
如果仔细观察,你会发现基本类型并不复杂,他们值包含简单的值,如i=0。
对象数据类型很复杂,它们会引用其它对象或基本类型。
换句话说,它要保持其它多种多样的引用,而每种类型必须存在内存中。
对象类型需要动态内存而基本类型需要静态内存。
如果需要分配动态内存,那么就分配到堆上;反之在栈上。
值类型与引用类型
现在我们明白了栈和堆,接下来看值类型和引用类型。
值类型的数据和内存在同一个位置,而引用类型是一个指向内存的指针。
下面示例是一个整形数据类型变量i被赋给另一个整形数据类型变量j。
它们的内存值都分配在栈上。
当我们把一个int值分配给另外一个int值时,需要创建一个完全不同的拷贝。
换句话说,你可以改变其中任何一个而不会影响另外一个。
这种数据类型被称为值类型。
当我们创建一个对象,并把一个对象赋给另外一个对象时,它们的指针指向相同的内存(如下图,当我们把obj赋给obj1时,它们指向相同的内存)。
换句话说,我们改变其中一个,会影响到另外一个,这种类型称为引用类型。
那么那种类型是值类型和引用类型呢?
在.NET中,依据数据类型,变量被分配到堆或栈上。
“string”和"Object"是引用类型,其他基本类型被分配到栈上,是值类型,如下图:
装箱与拆箱
通过上面学习,我们学到了很多有用的东西,其中最有用的是明白了当把数据从栈移动到堆上时会有性能损失。
如下图实例,当我们把一个值类型装箱为引用类型时,数据从栈移动到堆上。
反之,数据从堆移动到栈上。
这种在堆和栈之间的移动带来了性能的损失。
数据从值类型转变为引用
类型的过程称为“装箱”,反之为“拆箱”。
如果编译上面的代码,在ILDASM中看IL代码就会发下如何进行装箱拆箱操作的,如下:
装箱拆箱的性能影响
为了揭示装箱拆箱如何影响性能,我们把下面代码运行10000次。
一个函数有装箱操作,另一个只有简单代码。
我们用简单的计时器看它们的运行时间。
装箱函数耗时 3542 MS,无装箱操作的耗时2477MS。
这说明在实际项目中,除非必须,否则应避免装箱,拆箱操作。
备注:
最近在CodeProject上看到<6 important .NET concepts: - Stack, heap, Value t ypes, reference types, boxing and Unboxing>一文,个人觉得非常好,所以就翻一下给不想看英文的同学。
由于能力有限,翻译的不好,望大家多多包涵。