String类知识点

前言

有这么一段代码

1 public class TestMain
2 {
3     public static void main(String[] args)
4     {
5         String str0 = "123";
6         String str1 = "123";
7         System.out.println(str0 == str1);
8     }
9 }

运行结果是什么?答案当然是true。对,答案的确是true,但是这是为什么 呢?很多人第一反应肯定是两个"123"的String当然相等啊,这还要想。但是"=="在Java比较的根本不是两个对象的值,而是比较两个对象的引 用是否相等,和两个String都是"123"又有什么关系呢?或者我们把程序修改一下

1 public class TestMain
2 {
3     public static void main(String[] args)
4     {
5         String str2 = new String("234");
6         String str3 = new String("234");
7         System.out.println(str2 == str3);
8     }
9 }

这时候运行结果就是false了,因为尽管两个String对象都是"234",但是str2和str3是两个不同的引用,所以返回的false。OK,围绕第一段代码返回true,第二段代码返回false,开始文章的内容。

为什么String=String?

在JVM中有一块区域叫做常量池,关于常量池,我在写虚拟机的时候有专门提到http://www.cnblogs.com/xrq730/p/4827590.html。 常量池中的数据是那些在编译期间被确定,并被保存在已编译的.class文件中的一些数据。除了包含所有的8种基本数据类型(char、byte、 short、int、long、float、double、boolean)外,还有String及其数组的常量值,另外还有一些以文本形式出现的符号引 用。

Java栈的特点是存取速度快(比堆块),但是空间小,数据生命周期固定,只能生存到方法结束。我们定义的boolean b = true、char c = ‘c‘、String str = “123”,这些语句,我们拆分为几部分来看:

1、true、c、123,这些等号右边的指的是编译期间可以被确定的内容,都被维护在常量池中

2、b、c、str这些等号左边第一个出现的指的是一个引用,引用的内容是等号右边数据在常量池中的地址

3、boolean、char、String这些是引用的类型

栈有一个特点,就是数据共享。 回到我们第一个例子,第五行String str0 = "123",编译的时候,在常量池中创建了一个常量"123",然后走第六行String str1 = "123",先去常量池中找有没有这个"123",发现有,str1也指向常量池中的"123",所以第七行的str0 == str1返回的是true,因为str0和str1指向的都是常量池中的"123"这个字符串的地址。当然如果String str1 = "234",就又不一样了,因为常量池中没有"234",所以会在常量池中创建一个"234",然后str1代表的是这个"234"的地址。分析了 String,其实其他基本数据类型也都是一样的:先看常量池中有没有要创建的数据,有就返回数据的地址,没有就创建一个

第二个例 子呢?Java虚拟机的解释器每遇到一个new关键字,都会在堆内存中开辟一块内存来存放一个String对象,所以str2、str3指向的堆内存中虽 然存储的是相等的"234",但是由于是两块不同的堆内存,因此str2 == str3返回的仍然是false,网上找到一张图表示一下这个概念:

为什么要使用StringBuilder和StringBuffer拼接字符串?

大家在开发中一定有一个原则是"利用StringBuilder和StringBuffer拼接字符串",但是为什么呢?用一段代码来分析一下:

 1 public class TestMain
 2 {
 3     public static void main(String[] args)
 4     {
 5         String str = "111";
 6         str += "222";
 7         str += "111";
 8         str += "444";
 9         System.out.println(str);
10     }
11 }

分析一下代码运行过程:

1、第5行,去常量池中找"111",没找到,常量池中创建一个,str指向常量池中的“111”

2、第6行,去常量池中找拼接后的"111222",没找到,常量池中创建一个,str指向常量池中的“111222”

3、第7行,去常量池中找拼接后的"111222111",没找到,常量池中创建一个,str指向常量池中的“111222111”

4、第8行,去常量池中找拼接后的"111222111444",没找到,常量池中创建一个,str指向常量池中的“111222111444”

看到了吧,这就是String拼接字符串的坏处。我们最终只需要"111222111444",但是却给我们在常量池中创建了这么多中间常量"111"、"111222"、"111222111"。这意味着,用String拼接字符串可能会导致常量池中产生大量的无用的常量(万一创建的常量池中本身就有呢),消耗内存空间,虽然一两个String不算什么,但是积少成多,代码中各个地方都使用String拼接字符串,那就是极大的消耗

同时,这就是要使用StringBuilder和StringBuffer的原因,以StringBuilder为例:

 1 public class TestMain
 2 {
 3     public static void main(String[] args)
 4     {
 5         StringBuilder sb = new StringBuilder("111");
 6         sb.append("222");
 7         sb.append("111");
 8         sb.append("111");
 9         sb.append("444");
10         System.out.println(sb.toString());
11     }
12 }

StringBuffer和StringBuilder原理一样,无非是在底层维 护了一个char数组,每次append的时候就往char数组里面放字符而已,在最终sb.toString()的时候,用一个new String()方法把char数组里面的内容都转成String,这样,常量池中创建了一个最终产生的String,在需要对字符串进行拼接尤其是大量 拼接的地方,大量地节省常量池的空间。

StringBuffer和StringBuilder用法一模一样,唯一的区别只是StringBuffer是线程安全的,它对所有方法都做了同步,StringBuilder是线程非安全的,所以在不涉及线程安全的场景,比如方法内部,尽量使用StringBuilder,避免同步带来的消耗。另外,StringBuffer和StringBuilder还有一个优化点,如果可以估计到要拼接的字符串的长度的话,尽量利用构造函数指定他们的长度,避免数组扩容带来的消耗,这个之后写List的时候会专门写到。

小心陷阱

虽然说不要用“+”拼接字符串,因为会产生大量的无用常量,但也不是不可以,比如可以使用以下的方式:

1 public class TestMain
2 {
3     public static void main(String[] args)
4     {
5         String str = "111" + "222" + "333" + "444";
6         System.out.println(str);
7     }
8 }

这么做,实际上编译的时候,Java会把"111"、"222"、"333"、"444"都拼接直接拼接在一起当作一整个字符串来看,然后给str,实际上这样,在常量池中只有一个"111222333444",并不会产生无用的常量。不过这么写得很少,主要原因有两点:

1、例子比较简单,但实际上大量的“+”会导致代码的可读性非常差

2、待拼接的内容可能从各种地方获取,比如调用接口、从.properties文件中、从.xml文件中,这样的场景下尽管用多个“+”的方式也不是不可以,但会造成不方便

时间: 2024-10-25 22:31:41

String类知识点的相关文章

String类知识点整理

先来个面试题吧面试题一String a = "ab";String b = "a" + "b";sysout(a==b)答案是true还是false呢?我们来一起分析一下这个过程a变量创建时,会在常量池中开辟一块空间存放ab,然后将空间地址赋值给a:b变量创建时,编译器会自动将+的结果运算出来,相当于b == "ab",此时JVM会先判断常量池中是否存在,直接将该对象的地址引用赋值给b变量,因此a跟b都是指向的常量池中的同一块

使用AngularJs制作页面知识点汇总一:String类型和JSON相互转换

最近一周做了一个页面,制作的过程中遇到各种问题,从中可以看出本人的js基础还不够扎实,angularjs也只是刚入门的水平,现在将制作过程中遇到的问题一一汇总,方便以后查阅. 一.String类型和JSON相互转换 1.使用ng来转换 angularjs中有fromJson和toJson两个方法用于处理json和string类型之间的转换 var json = '{"name":"liSi", "password":"321"

String类的常用方法以及知识点总结

一,String的简介: 查阅API中的String类的描述,发现String 类代表字符串.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现. 一旦这个字符串确定了,那么就会在内存区域中就生成了这个字符串.字符串本身不能改变,但str变量中记录的地址值是可以改变的. 字符串的本质是一个字符的数组(String类一旦被创建,就不能被改变). 1.1,String常量池 为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,

关于String类的一些知识点

//原链接:https://blog.csdn.net/songylwq/article/details/7297004 String str=new String(“abc”); 紧接着这段代码之后的往往是这个问题,那就是这行代码究竟创建了几个String对象呢?相信大家对这道题并不陌生,答案也是众所周知的,2个.接下来我们就从这道题展开,一起回顾一下与创建String对象相关的一些JAVA知识. 我们可以把上面这行代码分成String str.=.“abc”和new String()四部分来

JAVA API(一)String类和StringBuffer类

1.String类和StringBuffer类 在程序中经常会用到字符串,所谓的字符串就是指一连串的字符,它是由多个单个字符连接而成的.字符串中可以包含任意字符,这些字符必须包含在一对双引号""之内,如"abc".在Java中定义了String和StringBuffer类来封装字符串,并提供了一系列操作字符串的方法,它们都位于java.lang包中,因此不需要导包就可以直接使用.下面将对String类和StringBuffer类详细讲解. 1.1String类的初始

深入分析Java的String类的方法与特点

字符串是任何编程语言都必须支持的变量类型,有些编程语言是直接提供了原生的变量类型,有些编程语言则使用语法特性以 SDK 的形式提供支持.在Java编程平台中,对字符串的支持使用了后者的形式,就是通过在 JDK中提供一个名为String的类,对应字符串这个变量类型. 源码分析 既然JDK中的String类对应了字符串变量类型,为了熟练地掌握Java中字符串相关的技能,我们必须深入地分析和研究一下这个类.编码界有一句名言叫做 "源码面前,了无秘密",因此,我们第一步就是来看看String类

黑马程序员——14,String相关知识点

------<ahref="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- /* 下面介绍的是String类相关方法的知识点 */ class Zifuchuan { public static void main(String[] args) //主函数 { String a="yiersan"

第八周 项目四-string类的构造

请构造String类的加.减运算.其中,s1 + s2将两个字符串的连接起来:s1 - s2是将s1的尾部空格和s2的前导空格去除后的连接. 提示:有指针成员,设计时要注意.这个,你懂的. #include <iostream> #include <Cstring> using namespace std; class String { public: String( ); //默认构造函数 String(const char *s); String(String &str

string类总结第一部分函数介绍

在前面几章,看了整个String类的源码,给每个方法都行写了注释,但是太过凌乱,今天我就把String类的方法整理归纳,然后再讲一下String类比较难以理解的部分 特此声明:本文篇幅较大,涵盖知识点较多,请耐着性子读下去,毕竟写文章不易,写知识性文章更加不易! 第一部分:函数介绍 这是第一部分的内容,由于String的函数较多,我将他们分为四大类,分别是构造性函数.转换性函数.功能性函数以及私有函数 私有函数:主要是把属性以及一些私有方法列出来 构造性函数:也就是字符串的构造器 转换性函数:负