• Java中字符串String的研究


    先看一个例子:

    String str1 = new String("abc");
          String str2 
    = new String("abc");
          
    if(str1 == str2)
          {
            System.out.println(
    "str1 == str2");
          }
          
    if(str1.equals(str2))
          {
            System.out.println(
    "str1 equals str2");
          }
          
          String str3 
    = "abc";
          String str4 
    = "abc";
          
    if(str3 == str4)
        {
          System.out.println(
    "str3 == str4");
        }
        
    if(str3.equals(str4))
        {
          System.out.println(
    "str3 equals str4");
        }
        
    if(str1 == str4)
        {
          System.out.println(
    "str1 equals str4");
        }
        
    if(str1.equals(str4))
        {
          System.out.println(
    "str1 equals str4");
        }

    运行结果:

    str1 equals str2
    str3 == str4
    str3 equals str4
    str1 equals str4

    为什么会出现这样的结果。。。这需要引入一些概念,其实很类似C++ 或C#之类,差别只是小小的。。。

    首先了解一个对象在内存中创建的区域:

    1.heap(即堆区):它是负责创建对象的,所有的创建出来的对象都是放在堆区的。所有new操作的创建的实例都存储在这里,包括用new String 创建的String。 
    2.stack(即栈区):它是负责存放局部变量,和成员变量的。所有的成员变量和局部变  量都放在这个区内,然后他通过一个引用指向栈区的对象或data segment(静态代码)区的静态数据。
    3.data segment(静态代码区):在这个区主要存放的是静态常量,和字符串常量(字符串池)。在类一开始被加载的时候此常量就被初始化放在这个区内,而且被全局所共享,所有的访问直接指向他即可。
    4.code segment(代码区):它是存放代码的区,所有的执行代码都放在此区内。通过对象的调用指向此区。

    如果没有重载equals方法,则equals是比较地址是否相等, == 比较值是否相等。 来一段demo

    public class CC 
      {
        
    int no = 0;
        
    public CC(int _no)
        {
         no 
    = _no; 
        }
      }

    CC c1 
    = new CC(1);
         CC c2 
    = new CC(2);
         CC c3 
    = c1;
         
    if(c1 == c2)
         {
           System.out.println(
    "c1 == c2");
         }
         
    if(c1.equals(c2))
         {
           System.out.println(
    "c1 equals c2");
         }
         
    if(c1 == c3)
         {
           System.out.println(
    "c1 == c3");
         }
         
    if(c1.equals(c3))
       {
         System.out.println(
    "c1 equals c3");
       }

    运行结果:

    c1 == c3
    c1 equals c3

    解释:equals判断两个内存地址是否相等,因为c1、c2都是用new实例化的,因此肯定是不同内存地址,因此equals肯定为false,因为c3是存的c1的引用,也就是c1在堆里的地址,所以为true

    ==判断两个内存中的内容是否相当,因为c1,c2都是new出来的2个不同对象,即使对象内的成员等一模一样,因此也为false,c3地址跟c1一样,因此内容也一样。

    在java api中对equal的解释是:

    equals 方法在非空对象引用上实现相等关系:

    自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
    对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
    传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
    一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
    对于任何非空引用值 x,x.equals(null) 都应返回 false。

    equals是可以被类重写的,因此判断的标准也跟具体类不一样了。

    像String,date等系统类已经将该方法重写。在String类中equals就被重写为判断字符串内容是否相当,而不是字符串地址。

    再看开篇的demo程序。

    结果是

    str1 equals str2
    str3 == str4
    str3 equals str4
    str1 equals str4

     解释一下,

    在String中, String str1 = new String("abc")方式是在堆里分配一块内存;String str3 = "abc"方式,首先会到静态存储区的字符串池中搜索是否有该值,有的话,这直接给str3返回该指针,否则在字符串池中分配内存创建该字符串。

    因此

    String str1 = new String("abc");
    String str2 = new String("abc");

    是在堆分配了两块独立内存

    String str3 = "abc";
    String str4 = "abc";

    执行第一句时,str3 = "abc"时候,先到静态存储区的字符串池中找,发现没有这个字符串,则创建之,第二句str4 = "abc" 逻辑跟第一句一样,这时字符串池中已有该串,则直接给str4返回了str3的地址。

    因此有开篇的运行结果就容易理解了。

    了解了这些特性,我们可以把一些常用字符串写到公共类里,设为static, 以后所有用到这些串的时候就不用再分配内存了

  • 相关阅读:
    洛谷 P2008 大朋友的数字
    [USACO10FEB]慢下来Slowing down
    HAOI2007 理想的正方形 单调队列
    滑动窗口
    双栈排序
    概率无向图模型与条件随机场的异同
    P-R曲线出现凹陷的原因
    MaskLab-实例分割(使用语义分割和方向特征精细化目标检测)
    模拟递归生成器
    递归生成器
  • 原文地址:https://www.cnblogs.com/jacktu/p/1333774.html
Copyright © 2020-2023  润新知