Jave中String的比较

 String a=new String("gg")不只是在堆中创建
准确的说是在堆中创建“gg”,然后复制到栈中的a对象中,这就是复制过程
而String str="abc";是直接在栈中创建(ghyghost认为有待参考文献)

所以,无论是String str="abc";中的str
还是String a=new String("gg")中的a
都是在创建它们的类或者线程的私有栈中生存,其生存周期同创建它们类或线程
当创建它们的类或线程死掉,它们也从栈中弹出,私有变量栈消失

关于这个问题可以看看java rules里面有涉及,但翻译的太烂,所以也不是很详细
最简单的做法运用IDE跟踪
Optimizeit配合JBuilder可以看到
在Optimizeit可以跟踪堆变量
在JBuilder中可以跟踪栈变量,跑一个程序看看就知道了

另外,只有String是在堆中创建,然后复制到栈中的
其他的基本类型都是在堆中创建然后传引用到栈中的
也就是说栈中都是引用,只有String要复制过来

对于String类型,在java中是个及其特殊的类型
在虚拟机的实现上
在一个类装载的时候,不管是明确还是隐含(主动的初始化过程)
虚拟机首先在堆中为对象的实例变量分配内存
所有对象中和它超类中的变量都要分配内存

并在类的变量池中对栈中的符号引用进行解析
解析成堆内存中实际地址的指针(也就是把内存地址和符号名称一一对上号)
解析阶段是类连接的最后阶段,也是最重要的连接阶段
目的就是为了把符号引用替换成直接引用
而这些符号引用就是在栈中的变量地址

下面说到重点了:
对于String变量
也和其他变量一样进行这样的初始化过程
然后在常量池中进行转换
但不同的是java虚拟机针对String类型在内存中单独有一个符号引用到直接引用(指针)的对应表,这个表是全局的
这个表对所有在虚拟机中出现过的String对象保留他们的引用转换
以后,再生成一个与表中已经保留过的String对象值相同的String实例
那么用String a = "asdf";方法生成的话,栈中的符号引用a指向的是这个全局String表,在这里进行符号引用到指针的转换
如果使用String a = new String("asdf");方法生成的话,那么栈中的符号引用指向的是调用该方法的对象的常量池,在那里进行符号引用到指针的转换

而使用String.intern()方法则可以将一个String类的保存到这个全局String表中
如果具有相同值的Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址
如果在表中没有相同值的字符串,则将自己的地址注册到表中

**********************************************************************************************************
正确使用String类的几点注意

    java.lang.String类对大家来说最熟悉不过了,我们写java程序很少能不用String的。本文讲述如何正确的使用String,内容主要涉及初始化、串联和比较等操作。

    首先我们必须清楚的一点是String类是final类型的,因此你不可以继承这个类、不能修改这个类。我们使用String的时候非常简单,通常都是String s = "hello",但是Java API中同时提供了一个构造函数为String(String s),因此你也可以这样使用String s = new String("hello"),对于后面这样初始化一个String的方式是不推荐的,因为new操作符意味着将会在heap上生成一个新的对象,如果这样的操作发生在一个循环中,那么代价是惨重的。比如
for(int i = 0;i<1000;i++)
{
    String s = new String("hello");
}
    这将会创建1000个String类型的对象,由于String类是final的,因此这样的操作事实上是每次都生成了一个新的String对象的。如果你使用String s = "hello";那么就可以实现复用了,为什么可以复用呢,下面会有解释。

    当我们使用"+"实现串联操作的时候,比如String s = "hello"+"world";其实是通过StringBuffer类的append()方法实现的,最后返回String给s。如果有兴趣的话,你可以写一个简单的例子,然后用javap看看虚拟机是如何工作的。在使用串联的时候我们同样应该注意String是final类,如果你需要多次串联比如:
String sql = "xxx";
sql = "xxxx";
sql = "ssssss";
那么为了提高效率节省空间,我们应该自己用StringBuffer来替代"+";

    通常对String的比较有两种情况,一个是使用==,另一个是使用equals()方法,注意==是对对象的地址进行比较的,而String中的equals()方法是覆盖了Object类的方法,并且实现为对String对象的内容的比较。所以String s1 = new String("hello");String s2 = new String("hello"),我们对s1和s2进行上述比较的时候,前者应该返回false,因为使用new生成的是两个不同的对象。后者应该返回true因为他们的内容是一样的,都是"hello"。那么如果我们还有一个String s3 = "hello";他和s1的比较应该是什么样子的呢,答案是s1==s3为false,equals的比较位true。事实上String类是维持着一个String池的,这个池初始化为空的,当我们String x = "hello"的时候,hello就会被放入这个池中,当我们再次String y = "hello"的时候,他首先去检查池中是否存在一个和hello内容一样的对象,如果存在的话就会把这个引用返回给y,如果不存在的话,就会创建一个并放入到池中。这样就实现了复用。在String有一个方法intern()他可以把String的对象放入到池冲并返回池中的对象。如果我们对s1(String s1 = new String("hello"))调用intern,s1 = s1.intern()这时候,我们再把s1和s3进行“==”的判断,你会发现结果返回true!
    看下面的例子

public class StringTest
{

    public static void main(String[] args)
    {
        String s1 = "hello";
        String s2 = new String("hello");
        String s3 = new String("hello");
       
        testString(s1,s2,s3);
        s2 = s2.intern();
        System.out.println("after s2.intern");
        testString(s1,s2,s3);  

     }
       private static void testString(String s1,String s2,String s3)
    {
        System.out.println("s1 = s2 is "+(s1==s2));
        System.out.println("s2 = s3 is "+(s2==s3));
        System.out.println("s1.equals(s2) is "+s1.equals(s2));
        System.out.println("s2.equals(s3) is "+s2.equals(s3));
    }
}
输出结果为
s1 = s2 is false
s2 = s3 is false
s1.equals(s2) is true
s2.equals(s3) is true
after s2.intern
s1 = s2 is true
s2 = s3 is false
s1.equals(s2) is true
s2.equals(s3) is true

 

 

1、构造string实例对象的方法

    A、采用双引号将java字符序列括起来,即通过构造字符串直接量的方式构造string实例对象。字符串直接量实际上是string实例对象的引用,  所以他可以调用string中的成员方法。

    例如:int n="abcdef".length();//直接量abcedf实际上是该对象的引用。

    B、采用new运算符,格式如下:new String(构造方法的参数列表);

        例如:new String();//构造了一个不含任何字符的String类的实例;

          new String("abc");//构造了字符序列为“abc”的String实例;

    C、通过运算符“+”或其他成员方法生成String实例对象。String实例对象一旦生成就不能修改他所包含的字符序列,但是可以通过旧的字符   串生成新的String实例对象。

    例如:String s="abc".toUpperCase();//等式右边将生成一个字符串,内容是字符串的ab的字母全部转化成大写字符,然后将新生                                             成的字符串的引用赋值给变量s。

    D、在java语言中,任何一种类型的数据都可以转化成String类型的数据。

    *对于基本类型的数据,转化格式为:String valueOf(基本数据类型数据);

    例如:double d=0.12;

              String s=String.valueOf(d);

    *对于引用数据类型,通过下面格式转化:引用数据类型数据.toString();

2、对字符串内字符的访问

    A、通过类成员方法:public char charAt(int index)

    例如:"abc".charAt(1)//返回字符b

    B、字符串中字符个数可以String成员方法:public int length()得到

3、字符串内容的比较,有两个方法:

    A、public int compareTo(String anotherString)//区分字符的大小写

    B、public int compareToIgnoreCase(String anotherString)//不区分字符大小写

    *若相等,则返回0

    *若anotherString大,则返回一个负数

    *若anotherString小,则返回一个正数

4、字符串常量、成员方法intern和运算符“==”

    A、类String本身负责维护一个字符串池。该字符串池存放字符串常量所指向的字符串实例,以及调用过类String成员方法intern后的字符实例。

    B、当一个字符串实例调用类String成员方法intern之后,类String所维护的字符串池也回含有与该字符串实例相同内容的字符串实例。

    C、用“==”比较两个在字符串池中所引用的内容是否相同。如:s1.intern()==s0.intern()

5、运算符“+”

    A、当“+”两侧的操作数是字符串实例的引用时,运算的结果将生成一个新的字符串实例。

    例如:“String”+"Literal"结果是:String Literal

    B、当“+”两侧的操作数之一是字符串实例的引用,而另外一个是其他类型数据时,则先会将另一个数据转化为字符串数据,再进行字符串间的“+”操作。

    例如:"No."+1结果是:No.1。

6、从字符串到基本数据类型数据

   A、把字符串转换成基本数据类型数据可以通过如下的方法:

      Bololean的成员方法:public static Boolean valueOf(String s)

      Byte的成员方法:public static Byte valueOf(String s)

      Short的成员方法:public static Short valueOf(String s)

      Intenger的成员方法:public static Intenger valueOf(String s)

      Float的成员方法:public static Float valueOf(String s)

      Double的成员方法:public static Double valueOf(String s)

   B、把基本数据类型包装类数据转换成基本数据类型数据可以通过如下的方法:

      Bololean的成员方法:public Boolean booleanValue ()

?/P>

      Byte的成员方法:public Byte byteValue ()

      Short的成员方法:public Short shortValue ()

      Intenger的成员方法:public Intenger intengerValue ()

      Float的成员方法:public Float floatValue ()

      Double的成员方法:public Double doubleValue ()

     例如:boolean b=Boolean.valueOf("true").booleanValue();//结果为true

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值