admin管理员组

文章数量:1794759

常用类——String类

常用类——String类

String类型(java.lang.String)

1.字符串的创建

常量池:

Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。

所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串,还包含类、方法的信,占用class文件绝大部分空间。

而运行时常量池,则是JVM虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

String a = "Hello World";

此种创建方式下,编译器首先检查常量池中是否含有此字符串常量,没有则创建,然后JVM会开辟一块堆内存存放一个隐式对象指向该字符串常量,接着在栈空间里创建a变量,a变量指向该块堆内存首地址。

String a = new String("Hello World");

此种创建方式下,直接在堆内存new一个对象,并在常量池中创建“Hello World”字符串,该对象指向常量池中的“Hello World”字符串,然后创建a变量,并将a变量指向该块堆内存首地址。

2.字符串的特性

String是一个不可变的字符序列String a1 = new String("Hello");String a2 = new String("World");a1 += a2;

此段代码执行时,首先在内存中分配一块空间,它的大小为a1和a2空间大小之和,然后将a1和a2的内容复制到该内存空间相应位置,最后将变量a1指向该内存空间。 nadi

public final class String implements java.io.Serializable, Comparable<String>, CharSequence{ /** The value is used for character storage. */ private final char value[]; /** The offset is the first index of the storage that is used. */ private final int offset; /** The count is the number of characters in the String. */ private final int count; /** Cache the hash code for the string */ 中外文学名著 private int hash; // Default to 0 ........}

从String源码中分析可发膜和护发素的区别知,String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。并且String类是通过char数组来存储字符串。

public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > count) { throw new StringIndexOutOfBoundsException(endIndex); } if (beginIndex > ersi指标ndIndex) { throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value);}

分析String类中的substring方法可以发现,该方法的操作并不改变原有字符串的值,而是返回了一个新的字符串对象,这也与String类是一个不可改变的字符序列相吻合。

字符串的比较

“==”比较的是两个字符串地址是否相同,而.equ美甲网站als()方法比较的是两个字符串内容是否相同。

情况一:

String s1 = new String("java")手机怎么清理;String s2 = new String("java");System.out.println(s1==ssu242); //falseSystem.out.println(s1.equals(s2)); //true

此段代码创建的是两个对象,他们有不同的堆空间,因此“==”为false;但内容相同,因此.equals()为true。

情况二:

String s1 = new String("java");String s2 = s1;System.out.println(s1==s2); //trueSystem.out.println(s1.equals(s2)); //true

此段代码中变量s1,s2指向的为同一堆空间,并且字符串内容相同,因此均为true。

情况三:

String s1 = "java";String s2 = "java";System.out.println(s1==s2); //trueSystem.out.println(s1.equals(s2)); //true

此段代码中,字符串创建红烧牛肉面的做法方式为隐式创建,即,将String视为基本数据类型,因此,若字符串值相同,则s1,s2指向同一对象;若不同,则指向不同对象。

情况四:

String s0="helloworld"; String s1="helloworld"; String s2=&高清图片库#34;hello"+"world"; System.out.println(s0==s1); //true 可以看出s0跟s1是指向同一个对象 System.out.println(s0==s2); //true 可以看出s0跟s2是指向同一个对象

厦门brt线路图 此段代码中的s0和s1特产零食中的"helloworld”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而"hello”和"world”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中"helloworld”的一个引用。

情况五:

String s0="helloworld"; String s1=new万物生歌词 String("helloworld"); String s2="hello" + new String("world"); s3="aaa"; String s4=s0+s3; System.out.println( s0==s1 ); //false System.out.println( s0==s2 ); //false System.out.println( s1==s2 ); //false System.out.println( s4=="helloworldaaa" ); //false

用new String() 创建styrofoam的字符串不是常量,不能在编俄罗斯概况译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。

s0还是常量池中"helloworld”的引用,s1因为无法在编译期确定,所以是运行时创建的新对象"helloworld”的引用,s2因为有后半部分new String(”world”)所以也无法在编译期确定,所以也是一个新创建对象"helloworld”的引用。

String s4=s0+s3是运行时才可知的,而"helloworldaaa"是在编译时就存放在常量池中的。在之前说过,String的所有函数都是返回的一个新字符串而不改变原字符串,因此+运算符会在堆中建立来两个String对象,这两个对象的值分别是"helloworld&干涉波治疗仪#34;和"aa信托公司待遇a",也就是说从字符串池中复制这两个值,接着在堆中创建两个对象,然后再在栈空间建立变量s4,将 "helloworldaaa"的堆地址赋给s4。

情况六:

String s0 = "ab"; final String s1 = "b"; String s2 = "a" + s1; System.out.println((s0 == s2)); // true

s1字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + s1和"a" + "b"效果是一样的。故上面程序的结果为true。

情况七:

String s0 = "ab"; final String s1 = getS1(); String s2 = "a" + s1; System.out.println("===========test10============"); System.out.println((s0 == s2)); // false private static String getS1() { return "b"; }

这里虽然将s1用final修饰了,但是由于其赋值是通过方法调用返回的,那么它的值只能在运行期间确定,因此s0和s2指向的不是同一个对象,故上面程序的结果为false。

3.String、StringBuffer、StringBuilder的区别

(1)可变与不可变:String是不可变字符串对象,StringBuilder和StringBuffer是可变字符串对象(其内部的字符数组长度可变)。

(2)是否多线程安全:String中的对象是不可变的,也就可以理解为常量,显然线程安全。StringBuffer 与 StringBuilder 中的方法和面膜怎么用功能完全是等价的,只是StringBuffer 中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是非线程安全的。

4.关于String str = new String("abc")创建了多少个对象?

这个问题在很多书籍上都有说到比如《Java程序员面试宝典》,包括很多国内大公司笔试面试题都会遇到,大部分网上流传的以及一些面试书籍上都说是2个对象,这种说法是片面的。

首先必须弄清楚创建对象的含义,创建是什么时候创建的?这段代码在运行期间会创建2个对象么?毫无疑问不可能,用javap -c反编译即可得到JVM执行的字节码内容:

很显然,new只调用了一次,也就是说只创建了一个对象。而这道题目让人混淆的地方就是这里,这段代码在运行期间确实只创建了一个对象,即在堆上创建了"abc"对象。而为什么大家都在说是2个对象呢,这里面要澄清一个概念,该段代码执行过程和类的加载过程是有区别的。在类加载的过程蝶香中,确实在运行时常量池中创建了一个"禅学abc"对象,而在代码执行过程中确实只创建了一个String对象。

因此,这个问题如果换成 String str = new String("abc")涉及到几个String对象?合理的解释是2个。

5.常用方法

1.int length(); 鱼图片大全 返回字符串的长度

2.int indexOf(int ch); 返回该字符串第一个ch字符所在的位置

3.int indexOf(String str); 返回该字符串子字符串str起始位置

4.int lastIndexOf(int ch); 返回该字符串最后一个ch字符的位置

5.int lastIndexOf(String str); 返回该字符串最后一个str子字符串的起始位置

6.String substring(int beginIndex); 从字符串某个位置到结束截取字符串

7. String substring(int beginIndex, int endIndex); 从字符串的某个起始位置到结束(不包括末位置)截取字符串

8.String trim(); 返回去除了前后空格的字符串

9.boolean equals( Obiect object ); 将自定字符串与指定对象比较

10.String toLowerCase(); 将字母转换成小写

11.String toUpperCase() 将字幕转换成大写

12.char charAt(int index); 获取字符串指定位子的字符

13 .String [] split(String regex ,int limit); 将字符串进行截取,返回子字符串数组

14.byte[] getBytes(); 将字符串转变为byte类型的数组

附:java.lang.StringAPI文档链接:String (Java SE 9 & JDK 9 )

参考资料:

String (Java SE 9 & JDK 9 )

深入理解Java中的String - 平凡希 - 博客园

本文标签: 常用String