zoukankan      html  css  js  c++  java
  • (ZT)咋这么多怪事啊?——String是引用类型吗?

    (ZT)咋这么多怪事啊?——String是引用类型吗?

    一,
    string是引用类型,那么比较两个实例应当是地址才是啊
    string s="hello";
    string t="hello";
    s,t不应当相等啊
    二,
    Console.WriteLine((object)1 == (object)1);//结果为false
    Console.WriteLine((object)"ok" == (object)"ok");//结果为true
    为什么?装箱值代表什么?
    三,
    string a = "hello",b=string.Copy(a),c = "hello" ;
    Console.WriteLine((object)a == (object)b);//false
    Console.WriteLine((object)a == (object)c);//true
    为什么?
    四,
    string s,t;
    s="ok";
    t=s;
    s="yes";//改变s并不会同时改变t
    这好像不符合引用类型的惯例吧?(跟值类型到是差不多)
    为什么string是不可改变的?
    string的定义跟其它类有什么不同吗?(例如StringBuild,不要把string的定义贴出来,说出原因就行了)
    其它的类,如果两个对象引用同一实例,改变之一,另一个也会变啊

    【lovingkiss】:
    一,
    string是引用类型,那么比较两个实例应当是地址才是啊
    string s="hello";
    string t="hello";

    string是特殊的引用类型~~——特殊情况特殊处理

    【fengyunluanwu】:
    MARK


    【lovingkiss】:
    关于string是值类型还是引用类型 
    当然了,string本质上肯定是引用类型,但是这个特殊的类却表现出值类型的特点:
    判断相等性时,是按照内容来判断的,而不是地址
    它肯定是一个引用类型没错,两个方面来看:

    1. class string继承自object,而不是System.ValueType(Int32这样的则是继承于System.ValueType)
    2. string本质上是个char[],而Array是引用类型,并且初始化时也是在托管堆分配内存的
    微软设计这个类的时候估计是为了方便操作,所以重写了操作符和Equals方法,不然的话我们判断string相等得这样:
    foreach(char c in s.ToCharArray()){...}
    但是另外一个常用的对象微软却没有帮忙重写等值判断的方法:Array
    这样int[] a = {1,2,3}和int b = {1,2,3},a == b?// false

    还有一个容易搞错的地方是按引用传递还是按值传递的问题:
    引用类型按引用传递,值类型按值传递,这些都不错。
    一个引用类型,比如System.Array类,作为参数向一个方法传递时,传送的是指针,但是这两种代码是不是就意味着等效?
    void Test(Array a)和void Test(ref Array a)
    结果是并不完全等效。
    如果在函数内部调用构造函数新建了对象并赋予参数,则函数外的变量不会受影响;
    比如a = new ...
    如果只是改动该参数(一个对象)的字段,则会有影响,此时加不加ref都是等效的。
    比如a[i] = ...
    而string类型的另外一个特殊性在于它是“不会变”的,每次操作string,都相当于新建了一个string对象,所以对于string来讲,void Test(String s)和void Test(ref String s)永远都是不一样的。在这里string再次表现出了值类型的特点,我们以为这是传值 - 实际上传送的还是地址,但是在操作的时候string被再次初始化,外部根本不能得到这个变化。
    对于变量作用域的概念来讲,微软这么设计也是合理的:既然是函数内部建立的对象,外部就应该没有访问这个对象的能力,函数结束后,这些对象就会被GC收集,同样不会影响外面的程序。
    ----------
    update on [23, August]
    string可以看作是char[]的包装但是实际上CLR并不是用托管的char[]来实现的:
    这里是关于string的索引器的代码:
    public char this[int index]
    {
          get
          {
                return this.InternalGetChar(index);
          }
    }
    而InternalGetChar函数则是:
    [MethodImpl(MethodImplOptions.InternalCall)]
    internal char InternalGetChar(int index);
    这里可以看到string的确是内部调用CLR方法实现的,而不是char[]的包装


    【lovingkiss】:
    三、
            Dim S As String, B As String
            S = "Abcd"
            B = String.Copy(S)
            If S = B Then
                MsgBox("相等") '提示相等
            Else
                MsgBox("不相等")
            End If
    我看不懂C#,是不是你最后转成了Object??

    【lovingkiss】:
    四、String确实是带有值类型特性的引用类型,似乎不需要理由吧?
    难道真的需要理由??——难道非要问微软为啥这么做??
    你可以考虑问问微软为啥要为了方便——把String弄得不伦不类的

    【lizhizhe2000】:
    1.String对一些操作符进行了重载
    2.String是一个不可变对象,因此才出现了StringBuilder类,楼上的兄弟讲述已经很明白了!

    【amandag】:
    这么早就起来学习,表扬先...


    一,
    string是引用类型,那么比较两个实例应当是地址才是啊
    string s="hello";
    string t="hello";
    s,t不应当相等啊
    ==============================================
    每个字符串都是一个字符串对象,但.NET有个字符串池的概念,如果用到了同样的字符串,会从字符串池中进行查找,而不是再new出来一个字符串。(如果你查看IL的指令,你会发现并没有newobj指令,而是一个特殊的IL指令 加载字符串),这是因为CLR有一个更为特殊的、高效的构造字符串对象的方式
    所以,"hello"在堆里只有一个,而s和t都是指向这个字符串的引用,它们当然是相等的

    二,
    Console.WriteLine((object)1 == (object)1);//结果为false
    Console.WriteLine((object)"ok" == (object)"ok");//结果为true
    为什么?装箱值代表什么?
    ========================================================
    这个问题和上一个问题类似..左边和右边的(object)1装箱后在堆里都有自己的一个新地址,但字符串不是这样地


    三,
    string a = "hello",b=string.Copy(a),c = "hello" ;
    Console.WriteLine((object)a == (object)b);//false
    Console.WriteLine((object)a == (object)c);//true
    ==================================================================
    还是和第一个类似,只有Copy的那一个堆里有新的地址

    四,
    string s,t;
    s="ok";
    t=s;
    s="yes";//改变s并不会同时改变t
    这好像不符合引用类型的惯例吧?(跟值类型到是差不多)
    为什么string是不可改变的?
    string的定义跟其它类有什么不同吗?(例如StringBuild,不要把string的定义贴出来,说出原因就行了)
    其它的类,如果两个对象引用同一实例,改变之一,另一个也会变啊
    ================================================================
    string虽然是引用类型,但确实有些值类型的样子,不能更改的原因的细节,
    1. 我们可以在一个字符串上进行各种操作,但字符串并不改变
    2. 操作字符串的时候不会出现线程同步的问题

    但是这种性能的提升和直接访问特性的代价是,string必须为sealed类型。因为CLR不希望我们添加自己的字段去破坏它。

    如果你还是不了解,我很建议你参考一下.NET框架程序设计这本书

    【Bote_China】:
    一、尽管 string 是引用类型,但相等运算符(== 和 !=)被定义为比较 string 对象(而不是引用)的“值”
    二、(object)1 == (object)1输出 False,这是因为int为值类型,预定义的引用类型相等运算符对值类型没有意义。强制转换创建对已装箱 int 值的两个单独实例的引用。
    三、变量 a和 b引用两个包含相同字符的不同 string 实例。



    【lovingkiss】:
    amandag(高歌) 的说法我表示怀疑

    如果s和t都是指向这个字符串的引用,它们当然是相等的——但是假如这时候我改变S的内容,就相当于我改变了他引用的空间??然后我再改变t,t的空间也变化?没有变量使用的字符串缓冲就被回收了?

    呵呵,这个我没有理论依据,不过是感觉
    1、String的比较,是微软特殊提供的,比较内容,而不是地址。——这点是肯定的
    2、字符串空间的存放,应该取决于变量声明吧?应该是声明的时候就已经定义出来空间了阿。——这点是感觉,否则我频繁的变化某个字符串的时候,岂不是每次都要改变变量所在的空间??






    【lovingkiss】:
    string s="helloabc";
    string t="hello";

    如果字符串缓冲的话,是不是s空间还要包括t空间阿?~~呵呵~~

    【lovingkiss】:
    string类型的另外一个特殊性在于它是“不会变”的,每次操作string,都相当于新建了一个string对象,所以对于string来讲,void Test(String s)和void Test(ref String s)永远都是不一样的

    【twtqing】:
    楼上的人都是高人 学习

    【JustLovePro】:
    mark

    【wzd24】:
    同意高歌的。

    Desire has no rest.
  • 相关阅读:
    数据库分库分表
    工作笔记----数据库分表
    工作笔记----数据提取
    Runnable和Thread的应用场景
    LeetCode题目按公司分类
    spring boot Java配置搭建ssm (二)
    spring boot java配置搭建ssm 小案例(IDEA)
    spring boot xml配置搭建 ssm 小案例(IDEA)
    连接查询
    限定、模糊、排序、多表查询(3)
  • 原文地址:https://www.cnblogs.com/samcn/p/1297998.html
Copyright © 2011-2022 走看看