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, 以后所有用到这些串的时候就不用再分配内存了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值