Java中的String介绍
一、概述
String是代表字符串的类,本身是一个最终类,使用final修饰,不能被继承。
二、String字符串的特征
1. 字符串在内存中是以字符数组的形式来存储的。
示例如下,可以从String的底层源码中看到。
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
/**
* Class String is special cased within the Serialization Stream Protocol.
*
* A String instance is written into an ObjectOutputStream according to
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[];
/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence. Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.value = "".value;
}
...
}
2.因为字符串是常量,所以本身是存储在方法区的常量池中。只要字符串的实际值一样,那么用的就是同一个字符串-->字符串是一个常量,字符串是被共享的。直接使用字符串赋值时,在常量池中创建一个字符串对象,然后将栈中的引用指向常量池中的对象。
例如:
String str = "abc";
//重新创建一个地址,使str指向该地址,栈内存直接指向方法区
str = "def";
//在方法区中查找,如果存在,再次指向原地址
str = "abc";
//在方法区中查找,如果存在,新对象也指向原地址
String str2 = "abc";
//栈内存指向堆内存,堆内存指向方法区
String str3 = new String("abc");
System.out.println(str == str2); //true
System.out.println(str == str3);
其中,str和str2的地址就是相同的。
当使用new关键字创建String对象时,先在常量池中创建一个字符串常量对象,然后再在堆中new一个字符串对象,将该对象的地址指向常量区;然后在栈中创建一个引用,指向堆中的对象。
String str3 = new String("abc");
相当于在内存中创建了两个对象。其内存结构图如下所示

3. 如果需要拼接多个字符串,建议使用StringBuilder。因为使用StringBuilder拼接一次只产生一个新的对象,而使用+要产生3个对象。 具体示例如下;
String[] arr = new String[100];
String result = ""; //1个对象:共301个
for(int i = 0; i < 100000; i++) {
//result = new StringBuilder(result).append(str).toString();
result += arr[i]; //没拼接一次,产生3个对象
} //共:102个对象
//产生一个对象
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 100000000; i++) {
//每拼接一次,创建一个对象;一共产生了100个对象
sb.append("a");
} result = sb.toString(); //1个对象
4. String类中,提供了一系列的字符串操作方法,但是都不改变原来字符串,都是产生一个新的字符串。
例如查看获取子串函数的源码
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
5. String字符串“+”在编译时和运行时的区别
预编译是指编译器会在编译时检测是否存在字符串字面量,如果有字面量相加的情况,会提前将字面量字符串进行合并并存储到常量池中。
/**
* 继续-编译期无法确定
*/
public void test5(){
String str1="abc";
String str2="def";
String str3 = "abc" +"def"
String str4 = str1 + str2;
System.out.println("===========test============");
System.out.println(str4 == str3 ); //false
}
返回结果分析:因为str4指向堆中的"abcdef"对象,而"abcdef"是字符串池中的对象,所以结果为false。JVM对String str="abc"对象放在常量池中是在编译时做的,而String str4= str1+str2是在运行时刻才能知道的。new对象也是在运行时才做的。而这段代码总共创建了6个对象,字符串池中两个、堆中三个。+运算符会在堆中建立起来两个String对象,这两个对象的值分别是通过StringBuilder创建"abc"和通过append方法创建"abcdef",最后通过toString方法再建立对象str4,然后将"abcdef"的堆地址赋给str4,而堆中的“abcdef”地址指向常量池中的地址。
步骤:
1) 栈中开辟一块空间存放引用str1,str1指向池中String常量"abc"。
2) 栈中开辟一块空间存放引用str2,str2指向池中String常量"def"。
3) 栈中开辟一块空间存放引用str3,str3指向常量池中String常量“abcdef”。
4) str1 + str2通过StringBuilder的最后一步toString()方法还原一个新的String对象"abcdef",因此堆中开辟一块空间存放此对象。
5) 引用str4指向堆中(str1 + str2)所还原的新String对象。
6) str4指向的对象在堆中,而常量str3对应的"abcdef"在池中,输出为false。
Java中的String介绍的更多相关文章
- 关于JAVA中的String的使用与连接(转)
JAVA中的String连接性能 Java中的String是一个非常特殊的类,使它特殊的一个主要原因是:String是不可变的(immutable). String的不可变性是Ja ...
- Java中的String与常量池[转帖]
string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...
- Java中的String与常量池
string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...
- (转)Java 中关于String的空对象(null) ,空值(empty),空格
原文出处:Java 中关于String的空对象(null) ,空值(empty),空格 定义 空对象: String s = null; 空对象是指定义一个对象s,但是没有给该对象分配空间,即没有实例 ...
- 转载:Java中的String与常量池
转载自http://developer.51cto.com/art/201106/266454.htm.感觉总结的不错,自己收藏一下. string是java中的字符串.String类是不可变的,对S ...
- 【转】java中Thread类方法介绍
原文: java中Thread类方法介绍 http://blog.csdn.net/seapeak007/article/details/53395609 这篇文章找时间分析一下!!!:http:// ...
- 我说精通字符串,面试官竟然问我 Java 中的 String 有没有长度限制?
String 是 Java 中很重要的一个数据类型,除了基本数据类型以外,String 是被使用的最广泛的了,但是,关于 String,其实还是有很多东西容易被忽略的. 就如本文我们要讨论的问题:Ja ...
- Java内存管理-探索Java中字符串String(十二)
做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 一.初识String类 首先JDK API的介绍: public final class String extends O ...
- (转)Java中的String与常量池
Java中的String与常量池 转自:http://developer.51cto.com/art/201106/266454.htm string是java中的字符串.String类是不可变的,对 ...
随机推荐
- SessionAttributes注解
SessionAttributes注解: a.该注解只能应用在类上: b.该注解用于将Map.ModelMap.Model或ModelAndView中的数据暂存到HttpSession中以使其可以在多 ...
- Hibernate all-delete-orphan[转]
博客分类: SSH 当关联双方存在父子关系,就可以在 set 处设定 cascade 为 all-delete-orphan 所谓父子关系,即指由父方控制子方的持久化圣明周期,子方对象必须和一个父 ...
- ROS-4 : ROS节点和主题
依照<ROS-3 : Catkin工作空间和ROS功能包>,创建catkin工作空间,并在起src下创建功能包ros_demo_pkg,依赖项为roscpp.std_msgs.action ...
- 吴裕雄--天生自然JAVA数据库编程:CallableStatement接口
DELIMITER // DROP PROCEDURE myproc // -- 删除过程 CREATE PROCEDURE myproc(IN p1 int,INOUT p2 int,OUT p3 ...
- java多条件查询SQL语句拼接的小技巧
问题: 一个界面有个多个文本框输入值(或下拉框)展示的查询条件,也就是组合条件查询,需要在java里面动态拼接SQL,where条件如何写? 解决思路: 在where关键字后面固定写 1=1, 若还有 ...
- mac flutter 创建过程及遇到的问题
参考: 1.入门: 在macOS上搭建Flutter开发环境 系统要求 2.mac配置环境变量 1.打开终端 2.clone flutter 命令: git clone -b beta https:/ ...
- 第3节 sqoop:4、sqoop的数据导入之导入数据到hdfs和导入数据到hive表
注意: (1)\001 是hive当中默认使用的分隔符,这个玩意儿是一个asc 码值,键盘上面打不出来 (2)linux中一行写不下,可以末尾加上 一些空格和 “ \ ”,换行继续写余下的命令: bi ...
- docker 运行ubuntu镜像 apt-get update 问题
docker运行ubuntu镜像后,apt-getupdate出现问题如下: 根据上面的报错大概是因为....文件上没有生效(生效还需要10d 13h 33min 45s),看来是时间不够啊,需要等待 ...
- redis学习记录1 特性与优点
1.存储结构:字符串.散列.列表.集合.有序集合. redis存储结构的优势:数据在redis中的储存方式和其在程序中的储存方式相近:redis对不同数据类型提供非常方便的操作方式,如使用集合类型储存 ...
- mybatis#mapper原理
mapper是比较神奇的东西,通过一个接口,不写实现类,就可以完成sql语句的执行. 通过对jdk的动态代理进行学习,开始明白了其中的原理. 一个demo: 文件1:Subject.java 对应的就 ...