求曾之乔的猜猜看 mp3mp3百度云资源

详解C#和Java中值类型和引用类型的区别
- 正文内容
关于C#、Java值类型和引用类型的区别,一直都是各软件公司的技术面试保留题。值类型和引用类型从原理上来讲就是在内存中存储记忆的方式不一样。例如我们在程序中声明两个int(值类型)类型。 int num1=2;int num2=num1;声明两个变量的操作相当于在内存中分别分配了两块 int (4个字节)这么大的空间。num1或num2分别是这两空间的名称,并且我们将num1这块空间的值复制给了num2这块空间,但是要注意的是num1和num2完全是两块独立且相互不受干扰的空间。例如:num1=3;打印的时候num1的值是3而num2的值是2。&然后我们来使用引用类型并进行对比。int [] nums1=new int[]{2,3};int [] nums2=nums1;这里我们声明两个数组类型(引用类型),但是需要注意的是引用类型需要使用实例化(创建)的操作来分配空间。虽然声明了两个数组变量但是目前两个变量使用的是同一块空间,上面的赋值操作只是将nums2做了个空间的指向,所以你在下面让nums1或者nums2的值修改之后两个数组会相互影响。例如:nums1[0]=4;这个时候你打印nums1[0]或者nums2[0]会得到相同的结果4。。。&&&
附件下载:
o 13:05o 21:04o 11:22o 10:46
嗨,请对本篇文章做个评价吧:
我有话说:
网友评论仅供其表达个人看法,不代表FXTT168观点博客访问: 283415
博文数量: 107
博客积分: 6020
博客等级: 准将
技术积分: 1031
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: 系统运维
一、明辨值类型和引用类型的使用场合
Item:Distinguish Between Value Types and Reference Types
这个条款讨论的是类型设计时候的tradeoff——是将类型设计为结构还是类。Bill Wagner先生给出了一个原则“值类型用于存储数据,引用类型用于定义行为(value types store values and reference types define behavior)”。
如何判断这个原则的适用性,Bill Wagner也给出了一个方法,那就是首先回答下面几个问题:
该类型的主要职责是否用于数据存储?
该类型的公有接口是否都是一些存取属性?
是否确信该类型永远不可能有子类?
是否确信该类型永远不可能具有多态行为?
如果所有问题的答案都是yes,那么就应该采用值类型。这样的判断确实有很好的理由支撑,但是我个人认为“将这4个问题回答为yes”还不足以构成采用值类型的全部理由。因为在很多项目实践中,我发现值类型带来的性能问题不可小视。值类型带来的性能问题主要有两个:
由于值类型实例在栈和托管堆之间的转换而导致的box/unbox,以及由此带来的托管堆上的垃圾。
值类型默认情况下采用的是值拷贝语义,如果是比较大的值类型,在传递参数和函数返回值时,同样会带来性能问题。
关于第1条,Bill Wagner在本条款中提到了“引用类型会给垃圾收集器带来负担”这个表面看似正确的判断。但是由于box/unbox的效应,有些情况下,反倒是值类型给垃圾收集器带来了更多的负担。比如将一些值类型放到一个集合中,然后又频繁地对其进行读写操作。如果碰到这种情况,我想“放弃结构而采用类”未尝不是一种更好的做法。事实上,将一个用作数据存储的值类型(比如System.Drawing.Point)添加到一个集合(System.Collections.ArrayList)中是一个太常见不过的操作。不过,C# 2.0中新引入的泛型技术对box/unbox的问题有极大的改善。
关于第2条,Scott Meyers先生在Effective C++的第22条“尽量使用pass-by-reference(传址),少用pass-by-value(传值)”中讲的比较清楚。虽然由于C#中的结构类型具有默认的深拷贝语义,没有拷贝构造器的调用。而且结构类型也没有子类,因此在某种程度上来讲不具有多态性,也就没有C++对象传值时可能出现的切割(slicing)效应。但是值拷贝的成本仍然不小。尤其是在这个值类型比较大的情况下,问题就比较严重。实际上,在.NET框架的Design Guidelines for Class Library Developers文档中,在说明什么时候应该使用结构类型的时候,其中提到了一项原则(还有其他一些并行原则)——类型实例数据的大小要小于16个字节。该文档主要是从类型的运行效率层面来考虑的,而Bill Wagner先生这里的条款主要是从类型的设计层面来考虑的。
从上述两条讨论来看,我个人倾向于对结构类型采取更为保守的设计策略。而对于类则可以积极大胆地使用。因为“将结构类型不适当地设计为类”带来的不良后果要远远小于“将类不适当地设计为结构类型”所带来的不良后果。就目前的经验来看,我甚至认为只有和非托管互操作打交道的情况才是使用结构类型最充足的理由,其他情况都要“三思而后行”。当然,在C# 2.0中引入泛型技术之后,box/unbox将不再是一个沉重的负担,应付一些非常轻量级的场合,结构类型依然有自己的一席之地。
&&& 内存的栈中;引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址。
值类型存取速度快,引用类型存取速度慢。
值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用
System.ValueType,引用类型继承自System.Object
C#中基本数据类型是值类型,结构也是值类型。而数组、类、接口、字符串都是引用类型。
以上是摘录作品。(第一条作者:李建忠)
阅读(1850) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。c#中的引用类型和值类型_C#应用_
c#中的引用类型和值类型
来源:人气:234
一,c#中的值类型和引用类型
& & &众所周知在c#中有两种基本类型,它们分别是值类型和引用类型;而每种类型都可以细分为如下类型:
&什么是值类型和引用类型
什么是值类型:
进一步研究文档,你会发现所有的结构都是抽象类型System.ValueType的直接派生类,而System.ValueType本身又是直接从System.Object派生的。根据定义所知,所有的值类型都必须从System.ValueType派生,所有的枚举都从System.Enum抽象类派生,而后者又从System.ValueType派生。 &
&所有的值类型都是隐式密封的(sealed),目的是防止其他任何类型从值类型进行派生。 & & &&
什么是引用类型:
在c#中所有的类都是引用类型,包括接口。
&区别和性能
值类型通常被人们称为轻量级的类型,因为在大多数情况下,值类型的的实例都分配在线程栈中,因此它不受垃圾回收的控制,缓解了托管堆中的压力,减少了应用程序的垃圾回收的次数,提高性能。
所有的引用类型的实例都分配在托管堆上,c#中new操作符会返回一个内存地址指向当前的对象。所以当你在创建个一个引用类型实例的时候,你必须要考虑以下问题:
内存是在托管堆上分配的
在分配每一个对象时都会包含一些额外的成员(类型对象指针,同步块索引),这些成员必须初始化
对象中的其他字节总是设为零
在分配对象时,可能会进行一次垃圾回收操作(如果托管堆上的内存不够分配一次对象时)
在设计一个应用程序时,如果都是应用类型,那么应用程序的性能将显著下降,因为这会加大托管堆的压力,增加垃圾回收的次数。
虽然值类型是一个轻量级的类型,但是如果大量的使用值类型的话,也会有损应用程序的性能(例如下面要讲的装箱和拆箱操作,传递实例较大的值类型,或者返回较大的值类型实例)。
由于值类型实例的值是自己本身,而引用类型的实例的值是一个引用,所以如果将一个值类型的变量赋值给另一个值类型的变量,会执行一次逐字段的复制,将引用类型的变量赋值给另一个引用类型的变量时,只需要复制内存地址,所以在对大对象进行赋值时要避免使用值类型。例如下面的代码
class SomRef
public int
struct SomeVal {
public int
class ogram {
static void ValueTypeDemo() {
SomRef r1 = new SomRef();//在堆上分配
SomeVal v1 = new SomeVal();//在栈上分配
r1.x = 5;//提领指针
v1.x = 5;//在栈上修改
SomRef r2 = r1;//只复制引用(指针)
SomeVal v2 = v1;//在栈上分配并复制成员
引用类型分配在托管堆上,值类型分配在线程栈上:其实这种说法的前半部分是对的,后半部分是错的。因为变量的值在它声明的位置存储的,所以假如某一个引用类型中有一个值类型的变量, 那么该变量的值总是和该引用类型的对象的其它数据在一起,也就是分配在堆上。(只有局部变量(方法内部声明的变量)和方法的参数在栈上)
结构是轻量级的类:这种错误的信息主要是因为有人认为值类型不应该有方法或者其它有意义的行为-它们应该作为简单的数据转移来使用,所以很多人分不清DateTime到底是值类型还是引用类型。
对象在c#中默认的是用过引用传递的:其实在调用方法的时候,参数值(对象的一个引用)是以传值得方式传递的,如果你想以引用方式传递的话,可以使用ref或者out关键字。
二,值类型的装箱和拆箱操作
1 int i = 5;
2 object o =
3 int j = (int)o;4 Int16 y=(Int16)o;
&什么是装箱,什么是拆箱
什么是装箱:所谓装箱就是将值类型转化为引用类型的过程(例如上面代码的第2行),在装箱时,你需要知道编译器内部都干了什么事:
在托管堆中分配好内存,分配的内存量是值类型的各个字段需要的内存量加上托管堆上所以对象的两个额外成员(类型对象指针,同步块索引)需要的内存量
值类型的字段复制到新分配的堆内存中
返回对象的地址,这个地址就是这个对象的引用
什么是装箱:将已装箱的值类型实例(此时它已经是引用类型了)转化成值类型的过程(例如上面代码的第3行),注意:拆箱不是直接将装箱过程倒过来,拆箱的代价比装箱要低的多,拆箱其实就是获取一个指针的过程。一个已装箱的实例在拆箱时,编译器在内部都干了下面这些事:
如果包含了&对已装箱类型的实例引用&的变量为null时,会抛出一个NullReferenceException异常。
如果引用指向的对象不是所期待的值类型的一个已装箱实例,会抛出一个InvalidCastException异常(例如上面代码的第4行)。 &
&它们在什么情况下发生,以及如何避免
static void Main(string[] args)
int v = 5;
object o =
Console.WriteLine(v+","+(int)o);
& & & 通过上面的分析我们已经知道了,装箱和拆箱/复制操作会对应用程序的速度和内存消耗产生不利的影响(例如消耗内存,增加垃圾回收次数,复制操作),所以我们应该注意编译器在什么时候会生成代码来自动这些操作,并尝试手写这些代码,尽量避免自动生成代码的情况。
你能一眼从上面的代码中看出进行了几次装箱操作吗?正取答案是3次。分别进行了哪三次呢,我们来看一下:第一次object o=v;第二次在执行&Console.WriteLine(v+","+(int)o);时将v进行装箱,然后对o进行拆箱后又装箱。也就是说装箱过程总是在我们不经意的时候进行的,所以只有我们充分了解了装箱的内部机制,才能有效的避免装箱操作,从而提高应用程序的性能。所以对上面的代码进行如下修改可以减少装箱次数,从而提高性能:
static void Main(string[] args)
int v = 5;
object o =
Console.WriteLine(v.ToString() + "," + ((int)o).ToString());//((int)o).ToString()代码本身没有任何意义,只为演示装箱和拆箱操作
下面来讨论一下编译器都会在什么时候自动生成代码来完成这些操作
使用非泛型集合时:比如ArrayList,因为这些集合需要的对象都是object,如果你将一个值类型的对象添加到集合中时会执行一次装箱操作,当你取值时会执行一次拆箱操作,所以在应用程序中应避免使用这种非泛型的集合。
大家都知道System.Object是所有类型的基类,当你调用object类型的非虚方法时会进行装箱操作(例如GetType方法)。在调用object的虚方法时,如果你的值类型没有重写虚方法也要进行装箱操作,所以在定义自己的值类型时,应重写object内部的虚方法(例如ToString方式)
将值类型转化为接口类型时也会进行装箱操作,这是因为接口类型必须包含对堆上的一个对象的引用。
三,泛型的出现(本节只简单介绍泛型对装箱和拆箱所起的作用,关于泛型的具体细节请参考下一篇文章)
泛型是CLR和编程语言提供的一种特殊机制,它在c#2中才被提供出来。
&它对避免装箱有什么作用?
在使用泛型时需要指定要装配的类型,这样可以减少装箱操作,比如下面的代码
static void Main(string[] args)
ArrayList dateList = new ArrayList {
DateTime.Now
IList&DateTime& dateT = new List&DateTime& {
DateTime.Now
使用ArrayList时,每添加一个时间都会进行一次装箱操作,而使用List&DateTime&时就不会进行装箱操作,从而提高应用程序的性能。
&C#中常见的泛型集合:
Dictionary&Tkey,Tvalue&;
HashSet&T&;
&在使用这些集合之前我们必须要理解每一种集合的工作原理(没事自己可以实现一下),了解每一种集合的适合场合,这样才能写出高效的代码。
四,在设计时如何选择类和结构体
在面试的时候,我们经常被问的一个问题(还有另外一个问题,如何选择抽象类和接口,下次我会单独聊聊这个问题),下面我们来聊聊在设计时应该如何选择结构体和类
&什么是结构体
结构体是一种特殊的值类型,所以它拥有值类型所以的特权(实例一般分配在线程栈上)和限制(不能被派生,所以没有 abstract 和 sealed,未装箱的实例不能进行线程同步的访问)。
&什么情况下选择结构体,什么情况下选择类
在大多数的情况下,都应该选择类,除非满足以下情况,才考虑选择结构体:
类型具有基元类型的行为
类型不需要从其它任何类型继承
类型也不会派生出任何其它类型
类型的实例较小(约为16字节或者更小)
类型的实例较大,但是不作为方法的参数传递,也不作为方法的返回值。
都说程序是一门注重实践的学科,但是也只有熟悉理解了这些概论的东西,才能在实践时写出优秀的代码,有不对或者不合理的地方欢迎在下面讨论;
优质网站模板新人求教一个C#关于值类型跟引用类型的例子问题!_c#吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:96,247贴子:
新人求教一个C#关于值类型跟引用类型的例子问题!收藏
using Susing System.Collections.Gusing System.Lusing System.Tnamespace Test04{
class Program
static void Main(string[] args)
ReferenceAndValue.Demonstration();//调用ReferenceAndValue类中的Demonstration方法
Console.ReadLine();
public class stamp//定义一个类
public string Name { }//定义引用类型
public int Age { }//定义值类型
public static class ReferenceAndValue//定义一个静态类
public static void Demonstration()//定义一个静态方法
stamp Stamp_1 = new stamp { Name = "Premiere", Age = 25 };//实例化
stamp Stamp_2 = new stamp { Name = "Again", Age = 47 };//实例化
int age = Stamp_1.A//获取值类型Age的值
Stamp_1.Age = 22;//修改值类型的值
stamp guru = Stamp_2;//获取Stamp_2中的值
/*Stamp_2 = Stamp_1;*/
Stamp_2.Name = "Again Amend";//修改引用的Name值
Console.WriteLine("Stamp_1's age:{0}", Stamp_1.Age);//显示Stamp_1中的Age值
Console.WriteLine("age's value:{0}", age);//显示age值
Console.WriteLine("Stamp_2's name:{0}", Stamp_2.Name);//显示Stamp_2中的Name值
Console.WriteLine("guru's name:{0}", guru.Name);//显示guru中的Name值
}}提问:假如把
/*Stamp_2 = Stamp_1;*/
的星号去掉,结果guru's name 为什么等于:Again
票牛教你如何买到热门、便宜、真实的演出门票!
&/* */&本来就是注释啊,去掉了就执行&Stamp_2 = Stamp_1&这条代码了
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或

我要回帖

更多关于 炎亚纶曾之乔最新消息 的文章

 

随机推荐