深入理解String类

String是java中的字符串。String类是不可变的,对String类的任何改变,都是返回一个新的String类对象。String不属于8种基本数据类型,String是一个对象。本文主要具体介绍一下String。

一、String在内存中的存储方式

例一:

public class TestString {

    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "abc";
        String str3 = "ab";
        String str4 = "ab"+"c";
        String str5 = str3 + "c";
        String str6 = new String(str2);

        System.out.println( str1 == str2 );  
        System.out.println( str1 == str4 );  
        System.out.println( str1 == str5 );  
        System.out.println( str1 == str6 );  
    }
}

答案: True True False False

  • 第一个断言很好理解,因为在编译的时候,”abc”被存储在常量池中,str1和str2的引用都是指向常量池中的”abc”。所以 str1str2 引用是相同的。
  • 第二个断言是由于编译器做了优化。在JVM中, 这个 String str4 = "ab"+"c"; 其实就是:String str4 = "abc";再在常量池中查找这个字符串是否存在,如果存在,则让变量直接引用该字符串。所以 str1str4 引用也是相同的。
  • 第三个断言可以参考api中关于String类的说明: Java 语言提供对字符串串联符号(”+”)以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的。 所以当 str5 最终将是一个在堆中存储的String对象,而 str1 是存储在常量池里面的, 所以不同。
  • str4 的对象不是显式赋值的,编译器会在堆中重新分配一个区域来存储它的对象数据。所以* str1和str6* 的引用是不一样的。(堆、栈、常量池见批注1)

二、String类中的常用方法

  1. 字符串比较 equals() ——判断内容是否相同。 compareTo() ——判断字符串的大小关系。 compareToIgnoreCase(String int) ——在比较时忽略字母大小写。 == ——判断内容与地址是否相同。 equalsIgnoreCase() ——忽略大小写的情况下判断内容是否相同。 reagionMatches() ——对字符串中的部分内容是否相同进行比较(详情请参考API)。
  2. 字符串查找 charAt(int index) ——返回指定索引index位置上的字符,索引范围从0开始。 indexOf(String str)——从字符串开始检索str,并返回第一次出现的位置,未出现返回-1。 indexOf(String str,int fromIndex);——从字符串的第fromIndex个字符开始检索str。 lastIndexOf(String str)——查找最后一次出现的位置。 lastIndexOf(String str,int fromIndex)—-从字符串的第fromIndex个字符查找最后一次出现的位置。 starWith(String prefix,int toffset)—–测试此字符串从指定索引开始的子字符串是否以指定前缀开始。 starWith(String prefix)——测试此字符串是否以指定的前缀开始。 endsWith(String suffix)——测试此字符串是否以指定的后缀结束。
  3. 字符串截取 public String subString(int beginIndex)——返回一个新的字符串,它是此字符串的一个子字符串。 public String subString(int beginIndex,int endIndex)——返回的字符串是从beginIndex开始到endIndex-1的串。
  4. 字符串替换 public String replace(char oldChar,char newChar)。 public String replace(CharSequence target,CharSequence replacement)——把原来的etarget子序列替换为replacement序列,返回新串。 public String replaceAll(String regex,String replacement)——用正则表达式实现对字符串的匹配。注意replaceAll第一个参数为正则表达式,鄙人曾经深受其害。
  5. 更多方法请参考API 拓展阅读:字符串处理(将字符串“ABCD”按照规律顺序输出ABCD,ABC,BCD,AB,BC,CD,A,B,C,D批注2)

三、String,StringBuffer与StringBuilder的区别?

String是不可变而StringBuffer是可变的,但是这可变与不可变究竟是什么意思呢?如果你能用IDE进行debug的话,你就会发现,String实例化以后所有的属性都是final的,而StringBuffer确不是,这就是可变与不可变。下面引用SCJP的试题来解释一下这个例子: 例二:

public class Test {   
    public static void stringReplace (String text) {   
        text = text.replace('j' , 'i');    
    }   

    public static void bufferReplace (StringBuffer text) {   
        text = text.append("C");    
    }   

    public static void main (String args[]) {    
        String textString = new String ("java");    
        StringBuffer textBuffer = new StringBuffer ("java");    

        stringReplace (textString);    
        bufferReplace (textBuffer);    

        System.out.println (textString + textBuffer);    
    }    
}  

答案: javajavaC

解释:String 是不可以变的字符串,StringBuffer 是可变的字符串. 对StringBuffer进行操作,是在原来的对象之上进行改变. 而对String进行操作,是创建新的对象. 假设调用stringReplace方法的参数text的内存地址是0x0001的话,在执行 text = text.replace(‘j’ , ‘i’); 以后,text的内存地址就会变成类似0x0002的地址,但是肯定不再是0x0001了,原因就是String类是final的,任何修改都将创造一个 新的字符串。那么在stringReplace方法里面输出text,就应该是0x0002地址里的内容了,iava。 总结: String:在String类中没有用来改变已有字符串中的某个字符的方法,由于不能改变一个java字符串中的某个单独字符,所以在JDK文档中称String类的对象是不可改变的。然而,不可改变的字符串具有一个很大的优点:编译器可以把字符串设为共享的。

**StringBuffer:**StringBuffer类属于一种辅助类,可预先分配指定长度的内存块建立一个字符串缓冲区。这样使StringBuffer类的append方法追加字符 比 String使用 + 操作符添加字符 到 一个已经存在的字符串后面有效率得多。因为使用 + 操作符每一次将字符添加到一个字符串中去时,字符串对象都需要寻找一个新的内存空间来容纳更大的字符串,这无凝是一个非常消耗时间的操作。添加多个字符也就意味着要一次又一次的对字符串重新分配内存。使用StringBuffer类就避免了这个问题.

StringBuilder:一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

批注1: 堆:由JVM分配的,用于存储对象等数据的区域。 栈:由JVM分配区域,用于保存线程执行的动作和数据引用。栈是一个运行的单位,Java中一个线程就会相应有一个线程栈与之对应。 常量池 :在编译的阶段,在堆中分配出来的一块存储区域,用于存储 显式 的String,float或者integer.例如String str=”abc”; abc这个字符串是显式声明,所以存储在常量池。 常量池拓展阅读:Java常量池详解之一道比较蛋疼的面试题 批注2: Question:将字符串“ABCD”按照规律顺序输出ABCD,ABC,BCD,AB,BC,CD,A,B,C,D。 首先分析字符串规律,理清思路这样处理起来才会得心应手。根据规律可以看出字符串的长度是从4->3->2->1这个大致可以知道分组需要循环4次,然后再看每组的字符串结构,可以通过图例很明显的看出(具体就不用解释了吧,图解释的很详细。。。)

代码:

String str = "ABCD";
        int len = str.length();
        for (int i = 1; i <= len; i++) {
            for (int j = 0; j < i; j++) {
                System.out.println(str.substring(j, len-i + j+1));
            }
        }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AILearning

字符串的学习

1> “==”与“equals”的区别 “==”判断的是两个字符串对象在内存中的首地址,就是判断是否是同一个字符串对象; 而equals()判断的是两个字符串对...

2015
来自专栏java学习

面试题53(考察求职者对String声明变量在jvm中的存储方法)

(单选题) 1、有如下一段代码,请选择其运行结果() public class StringDemo{ private static final Stri...

3033
来自专栏赵俊的Java专栏

删除元素

931
来自专栏我是攻城师

关于Java里面的字符串拼接,你了解多少?

字符串拼接是我们日常开发中很常见的操作,虽然常见,但要是使用不当的的话,很有可能让你的程序处理效率降低一大半,所以我们有必要来重新了解一下Java里面的字符串操...

1713
来自专栏学海无涯

16.Swift学习之结构体

862
来自专栏Golang语言社区

Go 语言数据类型

在 Go 编程语言中,数据类型用于声明函数和变量。 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充...

3237
来自专栏C/C++基础

C++抛出异常与传递参数的区别

C++的异常处理机制有3部分组成:try(检查),throw(抛出),catch(捕获)。把需要检查的语句放在try模块中,检查语句发生错误,throw抛出异常...

1033
来自专栏微信公众号:Java团长

Java反射机制深入详解

  反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和...

671
来自专栏Java技术栈

Java中创建String的两道面试题及详解

我们知道创建一个String类型的变量一般有以下两种方法: String str1 = "abcd"; String str2 = new String("ab...

3556
来自专栏三木的博客

Javascript中的数组

数组的定义: var colors = new Array(20); var colors = new Array('red');  // ['red'...

23910

扫码关注云+社区

领取腾讯云代金券