• 技术文章 >后端开发 >C#.Net教程

    C#基础知识整理:基础知识(11) 值类型,引用类型

    黄舟黄舟2017-02-11 13:25:40原创382
    C#是面向对象的语言,在面向对象的思想中,只有对象,所有事物都可以用类描述。所以比如这些,int,bool,char,string,double,long等都是类,那么像,30,2.5,"test"都是对应类的一个对象。

            static void Main(string[] args)
            {
                string istring = 30.ToString();
    
                string dstring = 2.5.ToString();
    
                string sstring = "test".ToString();
    
                Console.WriteLine(string.Format("{0},{1},{2}", istring, dstring, sstring));
    
                Console.ReadLine();
            }

    输出:

    可以看出它们有ToString()这个方法,所以它们是对象。
    在平时写代码时,定义数据类型除了上述的这种之外,肯定都用过:

             static void Main(string[] args)
            {
                Int32 i = 0;
    
                UInt32 j = 0;
    
                String str = "test";
    
                Console.ReadLine();
            }

    这个其实是.NET的一个机制,.NET是一个平台,这个平台上有C#,VB这些语言。因此,.NET定义了一系列类型,映射到不同的语言中,Int32在c#中就是int。这样的数据类型称作基元类型,在C#中类的对象必须使用new生成。而这一部分类直接就可以用常量表示。基元类型定义在.net Framework中,System命名空间下。看一下基元类型在C#语言中的类型映射。

    .NET Framework基元类型

    C#类型

    取值范围备注

    System.Boolean

    bool

    true/false/
    System.Bytebyte0 ~255

    无符号8位整数

    System.Sbytesbyte-128 ~ 127有符号8位整数
    System.Charchar0 ~ 65,535无符号16位整数
    System.Int16short

    -32,768 ~ 32,767

    有符号16位整数
    System.UInt16ushort0 ~ 65,535无符号16位整数
    System.Int32int-2,147,483,648 ~ 2,147,483,647有符号32位整数
    System.Int64long

    -9,223,372,036,854,775,808 ~

    9,223,372,036,854,775,807

    有符号64位整数
    System.UInt64ulong

    0 ~ 18,446,744,073,709,551,615

    无符号64位整数
    System.Singlefloat

    ±1.5 × 10-45 ~ ±3.4 × 1038

    (7位有效数字)

    32位单精度浮点数
    System.Doubledouble

    ±5.0 × 10-324 到 ±1.7 × 10308

    (15至16位有效数字)

    64位双精度浮点
    System.Decimaldecimal

    ±1.0 × 10-28 到 ±7.9 × 1028

    (27至28位有效数字)

    128位浮点数数
    System.Stringstring任意字符串/
    System.UInt32uint0 ~ 4,294,967,295无符号32位整数

    表中的除了string是引用类型(后面单独解释),其它都是值类型。
    下面简单介绍下引用类型和值类型。
    学习C语言的时候有个堆和栈的概念。
    堆区——程序员分配释放,或者程序结束有OS回收,分配方式类似于链表。
    栈区——由编译器自动分配释放,存放函数的参数值,变量值等。
    栈内存结构可以快速的分配内存和回收内存,但栈空间有限,过多使用会“溢出”,因此栈只分配常用的,占用空间小的数据类型;堆内存结构分配内存较慢,但是利用空间大,可以存放大型数据。
    在C#中,基本上所有的数据都存储在“堆”结构中,称之为“托管堆”,受.NET垃圾回收监控。但是相对于栈堆结构中内存分配效率比较低。为了正确进行垃圾回收,每次分配的堆空间比实际所需空间稍大,小型数据使用堆是不太合适的。
    可以比较看一下值类型和引用类型:
    C#中提供了Struct定义值类型,直接在栈上分配内存。

     /// <summary>
        /// 使用struct定义一个值类型,
        /// 值类型的只能实现接口,不能继承类
        /// </summary>
        public struct StructPositiveNumber : ICloneable  
        {
            /// <summary>
            /// 值类型字段
            /// </summary>
            private int number;
    
            /// <summary>
            /// 静态只读字段,作为类的初始值
            /// </summary>
            public readonly static StructPositiveNumber InitialValue = new StructPositiveNumber();
    
            /// <summary>
            /// 属性
            /// </summary>
            public int Number
            {
                get
                {
                    return number;
                }
    
                set
                {
                    if (value <= 0)
                    {
                        throw new Exception();
                    }
    
                    this.number = value;
                }
            }
            /// <summary>
            /// 可以定义构造器,但是和类不同,这里的默认构造器依然存在
            /// </summary>
            public StructPositiveNumber(int value)
            {
                if (value <= 0)
                {
                    throw new Exception();
                }
    
                this.number = value;
            }
    
            /// <summary>
            /// 实现克隆方法,返回当前对象
            /// </summary>
            /// <returns></returns>
            public object Clone()
            {
                return new StructPositiveNumber(this.number);
            }
        }

    调用

           static void Main(string[] args)
            {
                //声明变量,赋值
                StructPositiveNumber pNumber1 = StructPositiveNumber.InitialValue;
    
                pNumber1.Number = 1;
    
                //pNumber1赋给pNumber2
                StructPositiveNumber pNumber2 = pNumber1;
    
                //改变pNumber2的值
                pNumber2.Number = 2;
    
                //看打印结果,改变了pNumber2的值,但是不影响pNumber1
                Console.WriteLine(pNumber1.Number);//1
    
                Console.WriteLine(pNumber2.Number);//2
    
                //重新初始化pNumber2,通过构造器生成改变了初始值。
                pNumber2 = new StructPositiveNumber(3);
    
                Console.WriteLine(pNumber2.Number);//3
    
                //调用Clone将pNumber2复制给pNumber1
                pNumber1 = (StructPositiveNumber)pNumber2.Clone();
    
                Console.WriteLine(pNumber1.Number);//3
    
                //改变pNumber1的值,但是pNumber2值不改变
                pNumber1.Number = 4;
    
                Console.WriteLine(pNumber1.Number);//4
    
                Console.WriteLine(pNumber2.Number);//3
    
                Console.ReadLine();
            }

    结果

    再看引用类型定义的:

     public class ClassPositiveNumber : ICloneable
        {
            private int number;
    
            public int Number
            {
                get
                {
                    return this.number;
                }
    
                set
                {
                    if (value <= 0)
                    {
                        throw new Exception();
                    }
    
                    this.number = value;
                }
            }
    
            //引用类型自己可以初始化为null,无需定义初始值
            //public readonly static ClassPositiveNumber InitialValue = new ClassPositiveNumber();
    
            public ClassPositiveNumber(int value)
            {
                if (value <= 0)
                {
                    throw new Exception();
                }
    
                this.number = value;
            }
    
            public object Clone()
            {
                return new ClassPositiveNumber(this.number);
            }
        }

    调用

          static void Main(string[] args)
            {
                ClassPositiveNumber cNumber1;//默认值为null
    
                cNumber1 = new ClassPositiveNumber(1);
    
                ClassPositiveNumber cNumber2 = cNumber1;
    
                cNumber2.Number = 2;
    
                //可以看出,两个引用引用到了相同的对象
                Console.WriteLine(cNumber1.Number);//2
    
                Console.WriteLine(cNumber2.Number);//2
    
                //重新初始化cNumber2,之前的对象已被丢弃
                cNumber2 = new ClassPositiveNumber(3);
    
                Console.WriteLine(cNumber2.Number);//3
                
                //复制是复制一个对象的副本,因此,是两个不同的对象
                cNumber1 = (ClassPositiveNumber)cNumber2.Clone();
    
                Console.WriteLine(cNumber1.Number);//3
    
                cNumber1.Number = 4;
    
                Console.WriteLine(cNumber1.Number);//4
    
                Console.WriteLine(cNumber2.Number);//3
    
                Console.ReadLine();
            }

    结果

    通过例子,可以看出值类型的特点如下:
    a、使用struct声明;
    b、不能继承类,但是可以实现接口(当然除object类外);
    c、值类型使用值类型做为字段,但是字段无法有默认值;
    c、值类型中必须有默认构造器,而且自己定义构造器后,默认的无参数的构造器依然存在。而且在构造其中只能访问类中的字段,但是不能访问属性。符号=对于值类型来说是赋值,所以赋值是值类型变量不能为空,因为值类型没有引用的概念,肯定有值。

    以上就是C#基础知识整理:基础知识(11) 值类型,引用类型的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!

    声明:本文原创发布php中文网,转载请注明出处,感谢您的尊重!如有疑问,请联系admin@php.cn处理
    上一篇:C#基础知识整理:基础知识(10) 静态 下一篇:C#基础知识整理:基础知识(12) 超类Object
    php中文网线上培训班

    相关文章推荐

    • c语言中形参的缺省存储类别是什么• C++中内存泄漏的检测• C#的多线程机制初探(3)• 【c#教程】C# 预处理器指令

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网