1.String 类型的概述

Java中String就是Unicode字符序列,例如,字符串“Java\u2122”由5个Unicode字符J、a、v、a和 ™ 组成。不像C/C++中,字符串只是字符数组,Java中字符串String是一个java.lang包中的类。

但是,在Java中String和普通的类不一样,是一个特殊的类:

  • String可以直接使用双引号""进行赋值,而不用调用构造函数。
  • '+'可以拼接两个字符串,但是其他对象不能使用'+'。
  • String是不可变的,也就是说,String对象一旦创建就不能被修改。例如,toUpperCase() 方法创建并返回一个新字符串,而不是修改原理字符串的内容。

String类型的常用方法总结:

// 长度
int length() // 返回字符串的长度
boolean isEmpty() // 判断长度是否==0 // 比较
boolean equals(String another) // Java中不能使用 '==' 或者 '!=' 来比较两个字符串
boolean equalsIgnoreCase(String another)
int compareTo(String another) // 返回 0 如果字符串相同;< 0 如果字典序小于another;否则 > 0
int compareToIgnoreCase(String another)
boolean startsWith(String another)
boolean startsWith(String another, int fromIndex) // 在fromIndex位置开始
boolean endsWith(String another) // 检索 & 索引下标
int indexOf(String search)
int indexOf(String search, int fromIndex)
int indexOf(int character)
int indexOf(int character, int fromIndex)
int lastIndexOf(String search)
int lastIndexOf(String search, int fromIndex)
int lastIndexOf(int character)
int lastIndexOf(int character, int fromIndex) // 截取字符串的字符或一部分字符串(子串)
char charAt(int index) // 下标从 0 到 length - 1
String substring(int fromIndex)
String substring(int fromIndex, int endIndex) // 包前不包后 // 根据原字符串创建一个新字符串或字符数组
String toLowerCase()
String toUpperCase()
String trim() // 返回一个移除前后空白的新字符串
String replace(char oldChar, char newChar) // 返回一个替换后的字符串
String concat(String another) // 字符串拼接
char[] toCharArray() // 返回一个字符串数组
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) // 复制到 dst 字符数组中 // 静态方法,将基本类型转换为字符串
static String valueOf(type arg) // type可以是基本类型或者字符数组 // 静态方法,将字符串进行格式化输出
static String format(String formattingString, Object... args) // 类似于printf() // 正则表达式
boolean matches(String regex)
String replaceFirst(String regex, String replacement)
String replaceAll(String regex, String replacement)
String[] split(String regex)
String[] split(String regex, int limit)
静态方法 String.format()

这个方法用来输出一个格式化的字符串,类似于 C 系列的 printf() 函数。例如,

String.format("%.1f", 1.234);   // 返回字符串 "1.2"

String.format() 可以非常方便地用来输出一个简单格式的字符串(比如,在 toStirng() 方法中使用)。对于复杂的字符串,使用StringBuffer/StringBuilder加一个Formatter。

2. String 一个特殊的类

因为程序会频繁的使用 String 类型,String 类型在Java中是很特殊的。自然,为了计算性能和存储效率,String 的性能很关键。为了提高提高语言的性能,Java设计者们在面向对象语言中,保留了基本数据类型,而不是一切都是对象。基本数据类型存储在调用栈上,从而占用更少的存储空间,以及更容易维护。而对象实例存储在堆上,需要更复杂的内存管理和更多的存储空间。

为了更好地性能,Java 的 String 被设计成介于基本数据类型和普通类之间的一个特殊类型。Stirng 的特性包括:

  • 用于基本数据类型操作的'+',被 String 重载用来拼接两个字符串。出于软件工程的考虑,Java 不支持操作符的重载。在支持操作符重载的语言中,比如 C++ ,甚至可以将 '+' 重载用来执行减法运算,这会使得代码难以阅读。Java 中 '+' 只被内部重载用于字符串拼接。'+' 并不能用于任意两个对象中,比如 Points 或者 Circles。
  • String 有两种创建方式:直接赋值 或者 通过 new 关键字创建(这种方式不推荐,也不常见)

    举个例子:

    String str1 = "Java is Hot";           // 隐式地通过 String 字面量创建
    String str2 = new String("I'm cool"); // 显式地使用 new 创建

    在第一条语句中,str1 被申明为一个 String 类型引用,并被 String 字面量 "Java is Hot" 初始化。在第二条语句中,str2 被申明为一个 String 类型引用,并通过 new 关键字构造的 "I'm cool" String 对象初始化。

  • Stirng 字面量存储在常量池中,相同内容的字符串是共享的,只会存储一份。通过 new 创建的 String 对象存储在堆上,相同内容的字符串不会共享。

2.1 String 字面量 VS String 对象

如上所述,有两种方式构造 String :通过 String 字面量隐式地构造,或者通过 new 显式地创建。比如:

String s1 = "Hello";              // String 字面量
String s2 = "Hello"; // String 字面量
String s3 = s1; // 相同的引用
String s4 = new String("Hello"); // String 对象
String s5 = new String("Hello"); // String 对象

Java 提供一个特别的机制,字符串常量池,来保存 String 字面量。如果两个 String 字面量内容相同,它们将会在字符串常量池中共享。频繁使用的字符串将会通过这种方式持久地保存。另一方面,通过new 创建的 String 对象被保存在堆中。每个存储在堆上的 String 对象,就像其他对象一样,拥有独立的存储地址。堆上的存储地址不会共享,即使两个 String 对象内容相同。

可以使用 String 类的 equals() 方法比较两个字符串的内容。也可以使用 '==' 来比较两个对象的引用(或者叫指针)。看看下面的代码:

s1 == s1;         // true, 相同的引用
s1 == s2; // true, s1 和 s2 在常量池中共享
s1 == s3; // true, s3 被赋值为 s1 的引用
s1.equals(s3); // true, 内容相同
s1 == s4; // false, 对象引用不同
s1.equals(s4); // true, 内容
s4 == s5; // false, 堆上的引用不同
s4.equals(s5); // true, 内容相同

重点:

  • 在上面的例子中,通过'=='比较两个 String 对象的引用,说明了字符串存储在常量池和存储在堆上的区别。在程序中,使用 (str1 == str2) 来比较两个字符串的内容是逻辑上的错误。
  • String 直接赋值的内容将存储在字符串常量池中。不推荐使用 new 去创建一个堆上的字符串对象。

2.2 String 的不可变特性

因为字符串在常量池中是共享的,Java 的 String 被设计成不可变的。也就是说,一旦 String 被创建,它的内容就不能被修改。否则,其他共享内容的 Stirng 引用将会被无法预料变化影响。类似于 toUpperCase() 的方法就可能修改 String 对象的内容,而实际上它将返回一个新创建的 String 对象,原本的 String 对象引用会被释放,一旦没有引用了,就将会被GC。

因为 String 是不可变的,频繁修改 String 的效率很低(这将创建大量的字符串,并占用内存空间)。比如下面这段代码:

// 效率低的代码
String str = "Hello";
for (int i = 1; i < 1000; ++i) {
str = str + i;
}

如果需要频繁修改字符串,可以考虑使用 StringBuffer 或者 StringBuilder。

3. StringBuffer & StringBuilder

如前所述,字符串是不可变的,因为存储在字符串常量池中的字面量是共享的。修改其中一个字符串的内容,将会对其他共享的字符串产生副作用。

JDK 提供了两个类来支持可变的字符串:StringBuffer 和 StringBuilder(都在核心包 java.lang 中)。StringBuffer 和 StringBuilder 对象跟其他普通对象一样,存储在堆上,不会共享,因此修改它们不会对其他对象产生副作用。

StringBuilder 类是在JDK 1.5中引入的。它基本上与 StringBuffer 一致,除了它是线程不安全的以外。对于单线程的程序来说,StringBuilder 因为没有同步的开销,效率会更高。

必须知道的String知识点的更多相关文章

  1. Javascript:必须知道的Javascript知识点之“单线程事件驱动”

    heiboard: Javascript:必须知道的Javascript知识点之“单线程事件驱动”

  2. 深入理解.net - 4.你必须知道的String

    为什么要单独写string,主要是它太常用了,同时又太特殊了,特殊到CLR对它的处理都和其它对象不一样.简直可以称为VIP用户啊.本文并不是一篇介绍如何使用string的文章,而是旨在阐述string ...

  3. 【源码分析】你必须知道的string.IsNullOrEmpty && string.IsNullOrWhiteSpace

    写在前面 之前自信撸码时踩了一次小坑,代码如下: private static void AppServer_NewMessageReceived(WebSocketSession session, ...

  4. 你必须知道的MySQL知识点

    什么是索引 索引是帮助MySQL高效获取数据的排好序的数据结构 索引数据结构(掌握) 数据结构可视化 前置知识:树的高度越低查询效率越高 二叉树:不能自平衡,极端情况出现倾斜,查询效率和链表类似 红黑 ...

  5. 《jQuery风暴》第2章 必须知道的JavaScript知识

    第2章 必须知道的JavaScript知识 JavaScript是jQuery应用的基础,掌握JavaScript这门语言是使用jQuery的基础条件.本章不会全面细致的讲解JavaScript的全部 ...

  6. 必须知道的ADO.NET 数据库连接池

    http://www.cnblogs.com/liuhaorain/archive/2012/02/19/2353110.html 题外话 通过前几章的学习,不知道大家对ADO.NET有一定的了解了没 ...

  7. C语言学习书籍推荐《你必须知道的495个C语言问题》

    萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...

  8. 《你必须知道的.NET》读书笔记一:小OO有大智慧

    此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.对象  (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初 ...

  9. 《你必须知道的.NET》读书笔记二:小OO有大原则

    此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.单一职责原则 (1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因 (2)常用模式:Fa ...

随机推荐

  1. CentOS7为docker-ce配置阿里云镜像加速器

    一.找加速地址 https://promotion.aliyun.com/ntms/act/kubernetes.html 控制台 二.添加daemon.json 文件 vim /etc/docker ...

  2. Win10利用CodeBlocks搭建Objective-C开发环境(一)

    为了学习ios开发,而手头没有苹果机,若在windows平台下学习objective-c编程.则需要安装OC开发环境, 经过在网上查阅各种相关资料,历经多次失败,终于安装并测试成功,特将安装过程和经验 ...

  3. C#调试C++DLL库

    C#调试C++DLL库 https://blog.csdn.net/gggg_ggg/article/details/51086089 对于托管代码调用非托管DLL文件,已经是非常普遍的事情,下面写一 ...

  4. Java并发处理锁 Lock

    在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在 java.util.concurrent.locks 包下提供了另外一 ...

  5. Haproxy+keepalived高可用集群实战

    1.1  Haproxy+keepalived高可用集群实战 随着互联网火热的发展,开源负载均衡器的大量的应用,企业主流软件负载均衡如LVS.Haproxy.Nginx等,各方面性能不亚于硬件负载均衡 ...

  6. rsync同步本地和服务器之间的文件

    同步本地文件到服务器 rsync -zvrtopg --progress --delete test -e 'ssh -p 6665' yueyao@172.16.0.99:/media/sdb/us ...

  7. Java中XML的四种解析方式(二)

    三.JDOM解析 特征: 1.仅使用具体类,而不使用接口. 2.API大量使用了Collections类. import org.jdom2.Attribute; import org.jdom2.D ...

  8. Go语言学习笔记(10)——错误处理示例

    // 定义一个 DivideError 结构 type DivideError struct { dividee int divider int } // 实现 `error` 接口 func (de ...

  9. QQ、微信 唯一登陆设计

    唯一登陆设计指一个账号可以在多个不同的客户端进行登陆,例如PC.Android.IOS等.每一个客户端就会生成一个对应的tokan,相当于生成三个token分别对应不同的客户端. 但是同一个客户端同时 ...

  10. 记一次关闭Hadoop时no namenode to stop异常

    记一次关闭Hadoop时no namenode to stop异常 ​ 在自己的虚拟机环境上跑着hadoop集群,一直正常运行着,不用的时候直接挂起虚拟机,今天需要做些调整,但是发现集群突然无法正常关 ...