zoukankan      html  css  js  c++  java
  • 堆和栈,类型声明实例化过程,string=null;string=”“的区别;

    很多同学尤其是多数培训机构出来的同志,是直接学习的高级语言,诸如C#,JAVA

    开发倒是够了,但有时也会问些比较底层的东西。

    这里简单说一下,堆和栈,说到堆和栈又必须得说起引用,指针(被C#和JAVA屏蔽了,但是C#里可以写非安全型的指针)。

    值类型,引用类型,指针类型。

    区别:值类型直接入栈,引用类型通过指针访问,指针入栈,而该对象则在堆中,指针类型是特殊的类型,它也要分配内存,它的的值是所指向的对象的起始起址。

    通常在高级语言开发,不用关心指针,C#由CLR去管理。

    而且有非常重要的一点:C#和JAVA中,所说的对象的引用,其实质是指针,类似于C++和C语言的指针

    学过C语言或是C++的都知道,C语言里有也有引用。但这和C#面向对象的引用类型是两回事,而C#中的Ref,相当于C++和C语言的引用。

    以C语言里的声名方式为例。

    int a; 值类型。

    int &b=a;  声明一个int型的引用。int型为2字节,则引用的地址+引用对像的类型所占的字节数,便是引用对象的结束地址。

    声明对象的意义就是让程序知道,这个类型的对象所占的字节数。

    而b相当于a的别名,操作b与操作a是同样的。

    引用类型不占内存,主要用途是传值,指针类型则占内存,内存中的值,便是指向引用类型对象的首地址。

    C#里的,ref 在IL里便是被解析为 & 引用类型。

    详细请看这篇博文http://www.cnblogs.com/jacklondon/archive/2012/06/08/2542134.html

    C#中有指针,但必须在Unsafe代码块中,JAVA则完全不支持指针。

    首先我们要清楚,引用类型包括类、接口、委托和装箱值类型,string类型在IL被解析为String类型,也是引用类型。

      

    假设定义了一个类型Customer

    Customer cus; 声明一个Customer类型的引用(这实际是指针)。

    cus = new Customer();

     声明一个Customer类型的引用(指针的)的意义为两步。

    1:定义一个指针,入栈。指针还未指向任何对象。

    2:就是让程序知道,这个类型的对象所占的字节数,在内存中占多少空间。

    而实际上这时还没有该对象存在,指针没有指向任何地址。

    若只是声明,就使用该对象的属性或方法,理所当然出错。(根本不知道对象的入口在哪里)

    Ps:为指针分配内存时,内存中是有值的,是有指向的,但值未知的。

    再说操作对象属性和方法的过程。

    要知道

    对象的组成。对象内也不过是值和引用两种类型。

    而对象的方法,实际和对象内的引用类型类似,指向的是一个地址(区别是方法的入口,对象的入口)

    以值类型简单来说。假使A对象中有一个值类型属性c

    A a=new A();

    a.c

    在调a.c时.

    1先是在栈中找到A类的指针。

    2指针的值即对象的入口。对象保存在堆中。例地址为0x00000004 

    3c属性,是相对于对象起始地址(入口)的偏移量。

      想想后果,声明了一个对象,栈中分配了一个指针,指针的值未知(入口未知,偏移当然也是未知),天知道指哪去了,可能会指向另一个对象之中,这种操作,当然不安全。所以只声明不初始化。会有编译器会报错,有的编译时不报错,但在调属性或方法时出错。

    cus = new Customer(); 

    这一步才是真正的创建对象,在堆中分配内存,并把入口的地址保存在栈里指针cus的内存中,就是说,指针cus指向了堆里创建的这个对象。

      如果只这样写

    new Customer();  在堆中分配内存,但没有指针指向它,那就等垃圾回收了。

    而特别的

    cus=null;

    是C#或JAVA的实现,只声明,指针中的值是未知的。而指向null,只是一个标志。

    有些语言,会把只声明,实现为指向空,这是语言底层实现的差别

    不论是只声明(指针指哪没人知道),还是指向null(至少知道,指向为空),反正都没有指向真正的对象。

    所以不论语言实现为声明(指向任意),还是指向空。

    调用方法都会出错。

    这时再说string类型就很清楚了。

    string a; string a=null;  栈中有string类的指针,但要么指向值未知中,要么指向标志的Null,都没有真正的string对象。

    string a="";则已经有了一个string对象存在(先这么说,实际上这里还有个String池的处理)。

    我们知道,每实现一个对象,会在堆中新建。

    String类对象的特别之处,是多了一个String池

    string a="nimei" string b="nimei" a b 指向的同一个String对象,目的是为了省内存。

    但是String a=new String("nimei");String b=new String("nimei") a,b是不同的对象,每次NEW都在堆中新建一个新String.

    个人觉得,String池,实质上也是堆,一个特别的堆。

    再说点其他的

    string a=""  a在栈中,指向堆中一段“空”的String对象。

    说是空但并不是真空。

    C#和JAVA里可能没有提及。

    C语言里string的实质是一个char类型的数组。

    “abcde"的实际长度是6。

    内存中的值是 abcde/0  /0表示字符串的结束。

    所以C语言里string a=""; 实际是占内存的。内存的值就是/0;

    但C#里,String是一个对象,和C语言不同

    char数组有length属性。

    String对象有Length()方法。

     查IL,String类有个

    public char this[int index]
    { [MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical, __DynamicallyInvokable]
    get; }

    反回char类型的索引,再下面我是看不懂了。
    并没有明显的char[]存在,但是有一个GetEnumerbate方法
    public CharEnumerator GetEnumerator()
    {
        return new CharEnumerator(this);
    }
    
     
    public sealed class CharEnumerator : ICloneable, IEnumerator<char>, IEnumerator, IDisposable
    
    CharEnumerator 实现了IEnumerator<char> 接口

    String对象,也一定和char数组有关,是包括char数组的对象,一些属性,方法的对象。

  • 相关阅读:
    oracle中xhost报错
    cronolog切割apache和tomcat日志
    rsync配置和同步数据
    Jenkins+GitHub+maven
    Git只获取部分目录的内容
    git命令综合
    tomcat(不仅仅是tomcat)通过熵池解决在linux启动应用慢
    iptables之ipset集群工具
    Python中yield表达式的使用
    对于python中出现UnicodeDecodeError问题的解决方案
  • 原文地址:https://www.cnblogs.com/zihunqingxin/p/3132015.html
Copyright © 2011-2022 走看看