一、Java下

1、几个例子

  1. public static void main(String[] arge) {
  2.  
  3. String str1 = new String("1234");
  4. String str2 = new String("1234");
  5. System.out.println("①new String()方式下==:" + (str1 == str2));
  6. System.out.println("②new String()方式下equals:" + str1.equals(str2));
  7.  
  8. String str3 = "1234";
  9. String str4 = "1234";
  10. System.out.println("③赋值常量方式下==:" + (str3 == str4));
  11. System.out.println("④赋值常量方式下equals:" + str3.equals(str4));
  1. //3String val="1234";String str5 = val;String str6 = val;System.out.println("⑤赋值变量方式下==:" + (str5 == str6));System.out.println("⑥赋值变量方式下equals:" + str5.equals(str6)); 
  1. }

    运行输出:    

①new String()方式下==:false
②new String()方式下equals:true
③赋值常量方式下==:true
④赋值常量方式下equals:true
⑤赋值变量方式下==:true
⑥赋值变量方式下equals:true

2、代码分析

  (0)首先看下Java中String类里的equals是何如实现的  

  1. public boolean equals(Object anObject) {
  2. if (this == anObject) {
  3. return true;
  4. }
  5. if (anObject instanceof String) {
  6. String anotherString = (String)anObject;
  7. int n = value.length;
  8. if (n == anotherString.value.length) {
  9. char v1[] = value;
  10. char v2[] = anotherString.value;
  11. int i = 0;
  12. while (n-- != 0) {
  13. if (v1[i] != v2[i])
  14. return false;
  15. i++;
  16. }
  17. return true;
  18. }
  19. }
  20. return false;
  21. }

     (1)==是关系运算符,如果比较的双方是值类型,则比较的是两个值是否相等;如果比较双方是引用类型的对象,则比较的是两个对象的引用地址是否相同。

  (2)Java中String是引用类型。

  (3)第一个例子中,str1和str2是实例化出来的两个不同引用的对象,用==比较的对象的引用地址是否相同,所以结果为false;根据equals方法实现的代码可知,equals比较的是字符串的值是否相同,因为都是“1234”,所以毫无疑问,equals()比较返回true。

  (4)第二个例子中,是将同样的一个常量值"1234"分别赋值给str3、str4。实际上,当代码编译时,虚拟机会提取出值"1234",定义个常量(暂时叫t吧),将"1234"赋值给t,将t赋值给str3,然后将t赋值为str4,所以str3和str4指向的是同一块地址,结果就是==比较为true,equals和前面一样,依然是true。

  (5)第三个例子中,String val="1234";是将常量赋值给变量val,val指向这个"1234"常量的内存地址,String str5=val;是将val的引用赋值给了str5,String str6=val;也是将val的引用赋值给了str6。最终str5和str6同val一样,都指向了同“1234”这个常量内存地址。结果就是==比较为true。equals没有变化,还是true。

3、总结

(1) Java中的==,就是个关系运算符,始终遵守着它自己的规则,即:值类型比较久比较值,引用类型比较就比较内存地址。在String类中也是如此。

(2) String类中的equals()方法是重写了Object类的equals()方法,始终是比较两个字符串是否一样。

(3) 对于第二个例子,在编译器编译代码时,指定的字符串是个常量表达式,String类型的是引用类型,编译器先将常量表达式的内存地址赋值给一个常量,之后用到同样的字符串时,首先查看当前作用域中是否存在了同值的常量,如果存在就使用这个常量,导致指向了同一个内存地址。

二、C#下

1、几个例子

  1. static void Main(string[] args)
  2. {
  3.  
  4. String str1 = ', });
  5. String str2 = ', });
  6. Console.WriteLine("①new String()方式下==:" + (str1 == str2));
  7. Console.WriteLine("②new String()方式下equals:" + str1.Equals(str2));
  8.  
  9. String str3 = ";
  10. String str4 = ";
  11. Console.WriteLine("③赋值常量方式下==:" + (str3 == str4));
  12. Console.WriteLine("④赋值常量方式下equals:" + str3.Equals(str4));
  13.  
  14. String val = ";
  15. String str5 = val;
  16. String str6 = val;
  17. Console.WriteLine("⑤赋值变量方式下==:" + (str5 == str6));
  18. Console.WriteLine("⑥赋值变量方式下equals" + str5.Equals(str6));
  19.  
  20. Console.ReadLine();
  21. }

运行输出:

①new String()方式下==:True
②new String()方式下equals:True
③赋值常量方式下==:True
④赋值常量方式下equals:True
⑤赋值变量方式下==:True
⑥赋值变量方式下equals:True

2、代码分析

  (0) String类的Equals方法的实现,是实现对字符串是否相同的比较。

  1. public override bool Equals(object obj)
  2. {
  3. if (this == null)
  4. {
  5. throw new NullReferenceException();
  6. }
  7. string strB = obj as string;
  8. if (strB == null)
  9. {
  10. return false;
  11. }
  12. if (this == obj)
  13. {
  14. return true;
  15. }
  16. if (this.Length != strB.Length)
  17. {
  18. return false;
  19. }
  20. return EqualsHelper(this, strB);
  21. }
  22.  
  23. private static unsafe bool EqualsHelper(string strA, string strB)
  24. {
  25. int length = strA.Length;
  26. fixed (char* chRef = &strA.m_firstChar)
  27. {
  28. fixed (char* chRef2 = &strB.m_firstChar)
  29. {
  30. char* chPtr = chRef;
  31. char* chPtr2 = chRef2;
  32. )
  33. {
  34. if (*(((int*) chPtr)) != *(((int*) chPtr2)))
  35. {
  36. return false;
  37. }
  38. ))) != *((())))
  39. {
  40. return false;
  41. }
  42. ))) != *((())))
  43. {
  44. return false;
  45. }
  46. ))) != *((())))
  47. {
  48. return false;
  49. }
  50. ))) != *((())))
  51. {
  52. return false;
  53. }
  54. chPtr += ;
  55. chPtr2 += ;
  56. length -= ;
  57. }
  58. )
  59. {
  60. if (*(((int*) chPtr)) != *(((int*) chPtr2)))
  61. {
  62. break;
  63. }
  64. chPtr += ;
  65. chPtr2 += ;
  66. length -= ;
  67. }
  68. );
  69. }
  70. }
  71. }

    (1)String类中对==关系运算符进行了重写,也是实现了对字符串是否相同的比较。

  1. public static bool operator ==(string a, string b)
  2. {
  3. return Equals(a, b);
  4. }
  5.  
  6. public static bool Equals(string a, string b)
  7. {
  8. if (a == b)
  9. {
  10. return true;
  11. }
  12. if ((a == null) || (b == null))
  13. {
  14. return false;
  15. }
  16. if (a.Length != b.Length)
  17. {
  18. return false;
  19. }
  20. return EqualsHelper(a, b);
  21. }
  22.  
  23. private static unsafe bool EqualsHelper(string strA, string strB)
  24. {
  25. int length = strA.Length;
  26. fixed (char* chRef = &strA.m_firstChar)
  27. {
  28. fixed (char* chRef2 = &strB.m_firstChar)
  29. {
  30. char* chPtr = chRef;
  31. char* chPtr2 = chRef2;
  32. )
  33. {
  34. if (*(((int*) chPtr)) != *(((int*) chPtr2)))
  35. {
  36. return false;
  37. }
  38. ))) != *((())))
  39. {
  40. return false;
  41. }
  42. ))) != *((())))
  43. {
  44. return false;
  45. }
  46. ))) != *((())))
  47. {
  48. return false;
  49. }
  50. ))) != *((())))
  51. {
  52. return false;
  53. }
  54. chPtr += ;
  55. chPtr2 += ;
  56. length -= ;
  57. }
  58. )
  59. {
  60. if (*(((int*) chPtr)) != *(((int*) chPtr2)))
  61. {
  62. break;
  63. }
  64. chPtr += ;
  65. chPtr2 += ;
  66. length -= ;
  67. }
  68. );
  69. }
  70. }
  71. }

  (2)C#下String类也是引用类型,它通过重写Equals方法和==关系运算,最终都是通过EqualsHelper方法进行对字符串的比较,所以Equals和==实质上是相同的,没有区别。

  (3) 根据以上分析,所以返回值都是True,都是根据字符串是否相同进行比较,跟对象引用没有关系,导致结果是让人感觉String是个值类型,其实是微软通过对String进行改造,使之像是个值类型而已。

3、总结

    (1) C#下String类中的==已经不是一个纯粹的关系运算符了,它的作用是比较两个字符串是否一样的,同Equals方法一致。

    (2) 为什么微软将==改写,而不是保持==是个关系运算符的本质呢?

      MSDN上的话是:"尽管 string 是引用类型,但定义相等运算符(== 和 !=)是为了比较 string 对象(而不是引用)的值。 这使得对字符串相等性的测试更为直观。"

      但是我想,这个根本原因是理念不同导致的。大家都知道C#是后来借鉴Java来设计的,当初要修改Java的String设计,对==进行重写,初衷是为了更方便用户的理解,所以就算稍微违反一些语言程序的统一性、完成性、独立性等等各种性,也要修改这个设计,这就是一个商业产品的理念:"用户体验"更重要。

 

【原创】Java和C#下String类型中的==和equals的原理与区别的更多相关文章

  1. String类型中ToString hashCode equals compareTo等方法的经典实现

    private final char value[]; private int hash; // Default to 0 public String(String original) { this. ...

  2. java内存分配和String类型的深度解析

    [尊重原创文章出自:http://my.oschina.net/xiaohui249/blog/170013] 摘要 从整体上介绍java内存的概念.构成以及分配机制,在此基础上深度解析java中的S ...

  3. 【转】java内存分配和String类型的深度解析

    一.引题 在java语言的所有数据类型中,String类型是比较特殊的一种类型,同时也是面试的时候经常被问到的一个知识点,本文结合java内存分配深度分析关于String的许多令人迷惑的问题.下面是本 ...

  4. String类型中 "=="和"equals"比较的差别

    String类型中 "=="和"equals"比较的差别 先说明一下String类型的变量的创建方式 在创建新的String类型的变量时,首先会在缓冲区查找是否 ...

  5. Java日期的格式String类型GMT,GST换算成日期Date种类

    请尊重他人的劳动成果.转载请注明出处:Java日期格式化之将String类型的GMT,GST日期转换成Date类型 http://blog.csdn.net/fengyuzhengfan/articl ...

  6. 关于String类型中==和equals的区别。

    "=="操作符的作用 1.用于基本数据类型的比较,比较的是值. 2.用于比较对象,判断对象的引用是否指向堆内存的同一块地址. equals的作用 用于比较两个对象的内容是否相同 代 ...

  7. java对象转化成String类型

    在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能.本文将对常用的转换方法进行一个总结.常用的方法有Object#toString(),(String)要转换的对象,St ...

  8. Redis系列(四):数据结构String类型中基本操作命令和源码解析

    1.介绍 string类型本质上是char[]数组的封装  中文网:http://www.redis.cn/commands.html#string  2.常用命令 set 命令 set命令的时间复杂 ...

  9. Java用代码演示String类中的以下方法的用法

    用代码演示String类中的以下方法的用法 (1)boolean isEmpty(): 判断字符串是不是空串,如果是空的就返回true (2)char charAt(int index): 返回索引上 ...

随机推荐

  1. Tomcat 中响应头信息(Http Response Header) Content-Length 和 Transfer-Encoding

    户端(PC浏览器或者手机浏览器)在接受到Tomcat的响应的时候,头信息通常都会带上Content-Length ,一般情况下客户端会在接受完Content-Length长度的数据之后才会开始解析.而 ...

  2. HTML input小结

    一.Input表示Form表单中的一种输入对象,其又随Type类型的不同而分文本输入框,密码输入框,单选/复选框,提交/重置按钮等,下面一一介绍. 1.type=text 输入类型是text,这是我们 ...

  3. [nRF51822] 7、基础实验代码解析大全(前十)

    实验01 - GPIO输出控制LED 引脚输出配置:nrf_gpio_cfg_output(LED_1); 引脚输出置高:nrf_gpio_pin_set(LED_1); 引脚电平转换:nrf_gpi ...

  4. imagepool前端图片加载管理器(JavaScript图片连接池)

    前言 imagepool是一款管理图片加载的JS工具,通过imagepool可以控制图片并发加载个数. 对于图片加载,最原始的方式就是直接写个img标签,比如:<img src="图片 ...

  5. Atitit 索引技术--位图索引

    Atitit 索引技术--位图索引 索引在数据结构上可以分为三种B树索引.位图索引和散列索引 存储原理 编辑 位图索引对数据表的列的每一个键值分别存储为一个位图,Oracle对于不同的版本,不同的操作 ...

  6. IDEA设置代码大小以及菜单栏大小

    IntelliJ IDEA设置菜单栏大小的方法:File --Settings --Appearance & Behavior -- Appearance ,右边Override defaul ...

  7. Chart.js中文文档-雷达图

    雷达图或蛛网图(Radar chart) 简介 A radar chart is a way of showing multiple data points and the variation bet ...

  8. LINQ系列:LINQ to SQL Where条件

    1. 单一条件查询 var expr = context.Products .Where(p => p.ProductName == "LINQ to SQL"); SELE ...

  9. jQuery 2.0.3 源码分析 Deferred概念

    JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...

  10. Vue.js学习笔记(4)

    分享一段将 json数组数据以  csv格式导出的代码: html: <button class="btn btn-danger" @click='exportData'&g ...