Java基础(三) String深度解析
String可以说是Java中使用最多最频繁、最特殊的类,因为同时也是字面常量,而字面常量包括基本类型、String类型、空类型。
一. String的使用
1. String的不可变性
/**
* The {@code String} class represents character strings. All
* string literals in Java programs, such as {@code "abc"}, are
* implemented as instances of this class.
* <p>
* Strings are constant; their values cannot be changed after they
* are created. String buffers support mutable strings.
* Because String objects are immutable they can be shared. For example:
* ...
*/
public final class String {
private final char value[];
}
String对象一旦在堆中创建出来,就无法再修改。因为String对象放在char数组中,该数组由final关键字修饰,不可变。
2. 定义一个字符串
/**
* 定义一个字符串
*/
String str1 = "helloworld";
String str2 = "helloworld";
//也可以,但基本不这样写
String str3 = new String("helloworld");
System.out.println(str1 == str2);
System.out.println(str1 == str3);
//运行结果 true, false
上面三句代码怎么理解呢?这里需要先引入一个概念,字符串常量池。
字符串常量池是一块特殊的独立内存空间,放在Java Heap中 { 在Jdk7.0之前字符串常量池存放在PermGen中,Jdk7.0的时候移动到了Java Heap(在堆中仍然是独立的),Jdk8.0的时候去掉了PermGen,用Metaspace进行取代 } ,Java内存模型不是本章讨论的重点。
str1和str2引用的字符串字面量就在字符串常量池中,而str3引用的对象在Java Heap中。
怎么,还不太好理解?举个例子
工作一天,到下班时间了,准备看会儿金瓶.,算了,《三国演义》,打开小说网站,在线阅读;过了半个小时,女票回家了,看《三国演义》也是她想做的事儿,我看网址发给她,好,她也开始看了,再过半个小时,我爸回来了,他也是三国迷,但是他不喜欢在线看,因此在书店买了一本看。
上面提到的小说网站就是一个字符串常量池,包含了很多字符串字面量,如《三国演义》、《西游记》、《红楼梦》等,每个字符串字面量在常量池中保持独一份,无论谁进网站看《三国演义》都是同样的网址和同样的内容。
我和女票就是str1和str2,我们看的都是同一个网站的《三国演义》,不仅内容一样,引用的地址也一样(字符串常量池中保留了唯一的“helloworld”),因此str1 == str2 运行结果为true
而我爸就是str3,与我和女票都不一样,虽然看的内容也是《三国演义》,但是通过实体书籍来看,引用地址不一样,同时一本书籍不支持多个人同时看(字符串对象在java heap中,且每次new都会新建一个对象),因此str1 == str3 运行结果为false。
一个字符串字面量总是引用String类的同一个实例,因为被String.intern()方法限定了,同样我们可以调用该方法将堆中的String对象放到字符串常量池中,这样做可以提升内存使用效率,同时可以让所用使用者共享唯一的实例。
System.out.println(str1 == str3.intern());
//运行结果为true
那么该方法的实现逻辑是怎么样的呢,我们看一下源码
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
* It follows that for any two strings {@code s} and {@code t},
* {@code s.intern() == t.intern()} is {@code true}
* if and only if {@code s.equals(t)} is {@code true}.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
public native String intern();
我们发现这是一个native方法,看一下注释,发现str3.intern()方法大致流程是:
当执行intern()时,会先判断字符串常量池中是否含有相同(通过equals方法)的字符串字面量,如果有直接返回字符串字面量;如果不含,则将该字符串对象添加到字符串常量池中,同时返回该对象在字符串常量池的引用。
返回的引用需要赋值才可,否则还是会指向堆中的地址,即:
String str4 = new String("helloChina");
System.out.println(str4.intern() == str4);//false
str4 = str4.intern();
String str5 = "helloChina";
String str6 = "helloZhonghua"
System.out.println(str4 == str5);//true
下面我们看一下内存结构

3. 再次赋值给已定义的字符串
str6 = "helloHuaxia";
我们开始已经说了String是由final关键字修饰,不可变,那么此时在内存中如何体现呢?

4. String 对 “+” 的处理
String str7 = "good good" + " study";
String str8 = "good good study";
system.out.println(str7 == str8);
通过编译工具后得到
String str7 = "good good study";
String str8 = "good good study";
因此我们可以发现编译器在编译期间就是进行变量合并,而不会在常量池中创建三个对象 “good good”,“ study”,"good good study"。str7 == str8 运行结果 true。
但如果这样
String str9 = "good good ";
String str10 = str9 + "study";
system.out.println(str8 == str10);//false
这时运行结果为false,通过String变量 + 字符常量方式得到的结果会在堆中,不在常量池中,当然可以通过intern()方法放进常量池中,同时不仅“+”如此,调用substring(),toUpperCase(),trim()等返回的都是String在堆中的地址。
5. String常用的方法
//str1 == "hello,world ";
//获取长度
str1.length()//12;
//截取位置2到5之间的字符串(包括位置2,不包括位置5,从0开始)
str1.substring(2,5);//"llo"
//判断是否含有字符串“ello”
str1.contains("ello");//true,通过indexOf实现
//获取ello在str1中的开始位置
str1.indexOf("ello");//1
//将字符串转化为字符串数据
str1.split(",");//["hello","world"]
//去掉字符串两侧空格
str1.trim();//"hello,world"
二. 总结
本文从String的不可变性,String创建时字面量和String对象的不同,字符串字面量常量池,字符串的内存结构,常用的String相关方法的描述,若有不对之处,请批评指正,望共同进步,谢谢!
Java基础(三) String深度解析的更多相关文章
- Java基础常用类深度解析(包含常见排序算法)
目录 一.工具类 1.1.工具类的设计 1.1.1.公共静态方法 1.2.单例模式 二.包装类 2.1.基本类型的包装类 2.1.1.Integer 2.1.1.1.Integer >> ...
- Java基础-处理json字符串解析案例
Java基础-处理json字符串解析案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名开发人员,想必大家或多或少都有接触到XML文件,XML全称为“extensible ...
- Java 8 Optional 类深度解析
Java 8 Optional 类深度解析 身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法.我们首先要判断这个返回值是否为null,只 ...
- Java基础之String、StringBuffer、StringBuilder浅析
Java基础之String.StringBuffer.StringBuilder浅析 一.前言: 位于java.lang包下的String.StringBuilder.StringBuffer一般都是 ...
- String深度解析
文章出处:http://my.oschina.net/xiaohui249/blog/170013 一.引题 String类型是比较特殊的一种类型,同时也是面试经常被问到的一个知识点,本文结合java ...
- 3.Java基础:String对象的创建和使用
一.常用的创建方式 String s1=”abc“: String s2=”abc“: s1==s2 ==> true 解析:s1和s2指向的是同一个字符串池地址 二.不常用的创建方式 S ...
- 【Java基础】String 相关知识点总结
String 相关知识点总结 字符串的不可变性 概述 String 被声明为 final,因此它不可继承 在 Java8 中,String 内部使用 char 数组存储数据 public final ...
- Java基础之String中equals,声明方式,等大总结
无论你是一个编程新手还是老手,提到String你肯定感觉特别熟悉,因为String类我们在学习java基础的时候就已经学过,但是String类型有我们想象的那么简单吗?其实不然,String类型的知识 ...
- Java 基础三、接口与内部类
1. 在Java程序语言中,接口是对类的一种描述.例如Arrays类中sort方法声明可以对对象进行排序,但前提是对象所属的类必须实现Comparable接口. public interface ...
随机推荐
- 【29.41%】【codeforces 724D】Dense Subsequence
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- JAVA从本机获取IP地址
JAVA从本机获取IP地址 论述: 此篇博客是在工作的时候,需要获得当前网络下面正确的ip地址,在网上查阅很多博客,网上一个比较普遍的说法是通过InetAddress.getLocalHost().g ...
- C++重载加号运算符实现两个结构体的相加
#include<iostream> #include<string> using namespace std; struct S { int a, b; string str ...
- ElasticSearch的javaAPI之Client
翻译的原文:http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/client.html#node-c ...
- 一组西门子S7 报文
03 00 00 16 11 E0 00 00 00 01 00 C1 02 10 00 C2 02 03 01 C0 01 0A(第一次握手报文) 03 00 00 16 11 D0 00 01 0 ...
- Web 程序的建立
1 导读 web 基础研发体系指的是, web 研发中一线工程师所直接操作的技术.工具,以及所属组织架构的总和.在过去提升企业研发效能的讨论中,围绕的主题基本都是——”通过云计算.云存储等方式将底层核 ...
- Cocos2d-x layout (两)
相对于对照布局 Size widgetSize = Director::getInstance()->getWinSize(); Text* alert = Text::create(" ...
- 张量(tensor)的理解
1. 从标量到矢量:携带更丰富的信息 矢,是箭的意思,突出的特点是其指向性. 袋子里有几个球? 3 个,magnitude(幅度,没有单位): 从这到你家多远?3 km(denominate),3 称 ...
- .net中模拟键盘和鼠标操作
原文:.net中模拟键盘和鼠标操作 周银辉 其实SendKeys类提供的方法蛮好用的,可惜的是WPF中不能用了,说是WPF的消息循环方式改成了Dispatcher,所以直接调用System.Windo ...
- WPF 4 Ribbon 开发 之 标签工具栏(Tab Toolbar)
原文:WPF 4 Ribbon 开发 之 标签工具栏(Tab Toolbar) 本篇将开始介绍标签工具栏的开发内容,标签工具栏可以说是Ribbon 的核心部分,应用程序所有的功能特性都会集中 ...