字符串的学习,有的同学就看看API,记下方法,有的同学看看源代码,还有的同学画画图,自然学的深度是不一样的。
/** * 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: * <blockquote><pre> * String str="abc"; * </pre></blockquote><p> * is equivalent to: * <blockquote><pre> * char data[]={'a', 'b', 'c'}; * String str=new String(data); * </pre></blockquote><p> * Here are some more examples of how strings can be used: * <blockquote><pre> * System.out.println("abc"); * String cde="cde"; * System.out.println("abc" + cde); * String c="abc".substring(2,3); * String d=cde.substring(1, 2); * </pre></blockquote> * <p> * The class {@code String} includes methods for examining * individual characters of the sequence, for comparing strings, for * searching strings, for extracting substrings, and for creating a * copy of a string with all characters translated to uppercase or to * lowercase. Case mapping is based on the Unicode Standard version * specified by the {@link java.lang.Character Character} class. * <p> * The Java language provides special support for the string * concatenation operator ( + ), and for conversion of * other objects to strings. String concatenation is implemented * through the {@code StringBuilder}(or {@code StringBuffer}) * class and its {@code append} method. * String conversions are implemented through the method * {@code toString}, defined by {@code Object} and * inherited by all classes in Java. For additional information on * string concatenation and conversion, see Gosling, Joy, and Steele, * <i>The Java Language Specification</i>. |
String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。 字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。例如: String str="abc"; 等效于: char data[]={'a', 'b', 'c'}; String str=new String(data); 下面给出了一些如何使用字符串的更多示例: System.out.println("abc"); String cde="cde"; System.out.println("abc" + cde); String c="abc".substring(2,3); String d=cde.substring(1, 2); String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。大小写映射基于 Character 类指定的 Unicode 标准版。 Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。有关字符串串联和转换的更多信息,请参阅 Gosling、Joy 和 Steele 合著的 The Java Language Specification。 |
1、String是个final类
2、String是不可变的字符序列
public final class 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
String对象的字符内容是存储在一个字符数组中的。
private意味着外面无法直接获取字符数组,而且String没有提供value的get和set方法,
final意味着字符数组的引用不可改变,即通过让value指向新的数组对象来实现修改String对象,
而且String也没有提供方法来修改value数组某个元素值,因此字符串的字符数组内容也不可变。
疑问?那么字符串的拼接、字符串的截取、字符串的替换等操作是如何实现的呢?
每次修改都创建一个新的char数组表示修改结果。
3、String对象的创建
String str=“hello”;
String s1=new String(); // 本质上 this.value=new char[0];
String s2=new String(String original); //this.value=original.value;
String s3=new String(char[] a); //this.value=Arrays.copyOf(value, value.length);
String s4=new String(char[] a,int startIndex,int count)
.......
4、字符串对象是如何存储的
字符串常量存储在字符串常量池,目的是共享
字符串非常量对象存储在堆中。
5、String的拼接
结论:
常量与常量的拼接结果在常量池
只要其中有一个是变量,结果就在堆中
如果拼接的结果调用intern()方法,就在常量池中
6、String对象的比较
==比较的是地址。
equals比较的是字符串的内容,重写了Object的equals方法。
public boolean equals(Object anObject) {
if (this==anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString=(String)anObject;
int n=value.length;
if (n==anotherString.value.length) {
char v1[]=value;
char v2[]=anotherString.value;
int i=0;
while (n-- !=0) {
if (v1[i] !=v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
1、常用方法系列之一
l int length():返回字符串的长度: return value.length;
l boolean isEmpty():判断是否是空字符串:return value.length==0;
l String toLowerCase():使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
l String toUpperCase():使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
l String trim():返回字符串的副本,忽略前导空白和尾部空白。
l boolean equals(Object obj):比较字符串的内容
l boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
l String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
2、String类和字符相关操作
l char charAt(int index): 返回某索引处的字符return value[index];
l char[] toCharArray():将此字符串转换为一个新的字符数组
l String(char[] value):分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。
l String(char[] value, int offset, int count):分配一个新的 String,它包含取自字符数组参数一个子数组的字符。
3、String类字节与字符串操作方法
编码:把字符-->字节
l byte[] getBytes():使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
l byte[] getBytes(Charset charset) :使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
l byte[] getBytes(String charsetName) :使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
解码:把字节-->字符
l String(byte[] bytes) :通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
l String(byte[] bytes, Charset charset):通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。
l String(byte[] bytes, int offset, int length) :通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。
l String(byte[] bytes, int offset, int length, Charset charset):通过使用指定的 charset 解码指定的 byte 子数组,构造一个新的 String。
l String(byte[] bytes, int offset, int length, String charsetName):通过使用指定的字符集解码指定的 byte 子数组,构造一个新的 String。
l String(byte[] bytes, String charsetName):通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。
4、String类判断是否以指定内容开头或结尾
l boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束。
l boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始。
l boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
5、String类字符串查找操作
l boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true。
l int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。
l int indexOf(int ch, int fromIndex):返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
l int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。
l int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
l int lastIndexOf(int ch):返回指定字符在此字符串中最后一次出现处的索引。
l int lastIndexOf(int ch, int fromIndex):返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
l int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引。
l int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
indexOf和lastIndexOf方法如果未找到都是返回-1
6、String类字符串截取操作
l String substring(int beginIndex)
返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
l String substring(int beginIndex, int endIndex)
返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
7、String类是否匹配正则
l boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
public static void main(String[] args) {
String str="12345";
//判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches=str.matches("\\d+");
System.out.println(matches);
String tel="0571-4534289";
//判断这是否是一个杭州的固定电话
boolean result=tel.matches("0571-\\d{7,8}");
System.out.println(result);
}
8、String类替换操作
l String replace(char oldChar, char newChar):
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
l String replace(CharSequence target, CharSequence replacement):
使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
l String replaceAll(String regex, String replacement):
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
l String replaceFirst(String regex, String replacement):
使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
public static void main(String[] args) {
String str="12hello34world5java7891mysql456";
//把字符串中的数字替换成,,如果结果中开头和结尾有,的话去掉
String string=str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string);
}
9、String类字符串拆分操作
l String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
l String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
public static void main(String[] args) {
String str="hello|world|java";
String[] strings=str.split("\\|");
for (String string : strings) {
System.out.println(string);
}
String str2="hello.world.java";
String[] strings2=str2.split("\\.");
for (String string : strings2) {
System.out.println(string);
}
}
往期精彩内容:
Java常用类_包装类Wrapper
我们考虑以下多行SQL字符串:
UPDATE "public"."office"
SET ("address_first", "address_second", "phone")=(SELECT "public"."employee"."first_name",
"public"."employee"."last_name", ?
FROM "public"."employee"
WHERE "public"."employee"."job_title"=?
众所周知,在JDK 8之前,我们可以以多种方式将这段SQL包装成Java字符串(字符串字面量)。
在JDK 8之前
可能最常见的方法是使用众所周知的"+"运算符进行直接连接。这样,我们得到如下的多行字符串表示:
String sql="UPDATE \"public\".\"office\"\n"
+ "SET (\"address_first\", \"address_second\", \"phone\")=\n"
+ " (SELECT \"public\".\"employee\".\"first_name\",\n"
+ " \"public\".\"employee\".\"last_name\", ?\n"
+ " FROM \"public\".\"employee\"\n"
+ " WHERE \"public\".\"employee\".\"job_title\"=?";
编译器应该(并且通常是)足够智能,将"+"操作内部转换为StringBuilder/StringBuffer实例,并使用append()方法来构建最终的字符串。但是,我们可以直接使用StringBuilder(非线程安全)或StringBuffer(线程安全),如以下示例所示:
StringBuilder sql=new StringBuilder();
sql.append("UPDATE \"public\".\"office\"\n")
.append("SET ...\n")
.append(" (SELECT...\n")
// ... 省略其他部分
另一种方法(可能不如前两种流行)是使用String.concat()方法。这是一个不可变操作,基本上将给定的字符串附加到当前字符串的末尾。最后,它返回新的组合字符串。尝试附加null值将导致NullPointerException(在前面的两个示例中,我们可以附加null值而不会引发任何异常)。通过链接concat()调用,我们可以像以下示例一样表示多行字符串:
String sql="UPDATE \"public\".\"office\"\n"
.concat("SET...\n")
.concat(" (SELECT...\n")
// ... 省略其他部分
进一步来说,我们有String.format()方法。只需使用%s格式说明符,我们就可以在多行字符串中连接多个字符串(包括null值),如下所示:
String sql=String.format("%s%s%s%s%s%s",
"UPDATE \"public\".\"office\"\n",
"SET ...\n",
" (SELECT ...\n",
// ... 省略其他部分
虽然这些方法如今仍然很流行,但让我们看看JDK 8在这个话题上有什么要说的。
从JDK 8开始
从JDK 8开始,我们可以使用String.join()方法来表示多行字符串。此方法也专门用于字符串连接,它允许我们的示例具有清晰的可读性。如何实现?此方法将分隔符作为第一个参数,并在要连接的字符串之间使用此分隔符。因此,如果我们认为\n是我们的行分隔符,那么它只需要指定一次,如下所示:
String sql=String.join("\n",
"UPDATE \"public\".\"office\"",
"SET (\"address_first\", \"address_second\", \"phone\")=",
" (SELECT \"public\".\"employee\".\"first_name\",",
" \"public\".\"employee\".\"last_name\", ?",
" FROM \"public\".\"employee\"",
" WHERE \"public\".\"employee\".\"job_title\"=?;");
除了String.join()方法外,JDK 8还提供了java.util.StringJoiner。StringJoiner支持分隔符(如String.join())但也支持前缀和后缀。表达我们的多行SQL字符串不需要前缀/后缀;因此分隔符仍然是我们最喜欢的功能:
StringJoiner sql=new StringJoiner("\n");
sql.add("UPDATE \"public\".\"office\"")
.add("SET (\"address_first\", ..., \"phone\")=")
.add(" (SELECT \"public\".\"employee\".\"first_name\",")
// ... 省略其他部分
最后,谈到JDK 8就不能不提它的强大的Stream API。更具体地说,我们对Collectors.joining()收集器感兴趣。这个收集器的工作方式与String.join()相同,在我们的例子中,它看起来像这样:
String sql=Stream.of(
"UPDATE \"public\".\"office\"",
"SET (\"address_first\", \"address_second\", \"phone\")=",
" (SELECT \"public\".\"employee\".\"first_name\",",
" \"public\".\"employee\".\"last_name\", ?",
" FROM \"public\".\"employee\"",
" WHERE \"public\".\"employee\".\"job_title\"=?;")
.collect(Collectors.joining(String.valueOf("\n")));
所有前面的示例都有一个共同的缺点。最重要的是,这些示例中没有一个是真正的多行字符串字面量,每行之间的转义字符和额外引号严重影响了可读性。幸运的是,从JDK 13(作为未来预览)到JDK 15(作为最终功能),新的文本块已成为表示多行字符串字面量的标准。让我们看看如何实现。
引入文本块(JDK 13/15)
JDK 13(JEP 355)引入了一个预览功能,旨在为多行字符串字面量提供支持。在JDK 15(JEP 378)的两个版本中,文本块功能已成为最终且永久可用的功能。但是,让我们快速看看文本块如何塑造我们的多行SQL字符串:
String sql="""
UPDATE "public"."office"
SET ("address_first", "address_second", "phone")= (SELECT "public"."employee"."first_name",
"public"."employee"."last_name", ?
FROM "public"."employee"
WHERE "public"."employee"."job_title"=?""";
这太棒了,对吧?!我们立即注意到SQL的可读性已经恢复,我们没有混淆分隔符、行终止符和连接。文本块简洁、易于更新且易于理解。在SQL字符串中额外的代码足迹为零,Java编译器将尽最大努力以尽可能可预测的方式创建字符串。以下是嵌入JSON信息的另一个示例:
String json="""
{
"widget": {
"debug": "on",
"window": {
"title": "Sample Widget 1",
"name": "back_window"
},
// ... 省略其他部分
}""";
那么,如何用文本块表示HTML呢?
String html="""
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>John</td>
<td>Smith</td>
<!-- 这里有一个错误,缺少年龄单元格 -->
</tr>
</table>"""; // 注意这里修正了原始代码中的错误,应该是</table>而不是<table>
挂接文本块语法
文本块的语法相当简单。没有花哨的东西,也没有复杂的事情,只需要记住两个方面:
1. 文本块必须以"""(即三个双引号)和换行符开始。我们称此构造为开放分隔符。
2. 文本块必须以"""(即三个双引号)结束。"""可以单独放在一行(作为新行)或放在文本的最后一行末尾(如我们的示例所示)。我们称此构造为关闭分隔符。但是,这两种方法之间存在语义差异(在下一个问题中详细讨论)。
在此上下文中,以下示例在语法上是正确的:
String tb="""
I'm a text block""";
String tb="""
I'm a text block
""";
// ... 其他正确示例
另一方面,以下示例是不正确的,并会导致编译器错误:
String tb="""I'm a text block"""; // 错误:缺少换行符
// ... 其他错误示例
但是,请考虑以下最佳实践。
通过查看前面的代码片段,我们可以为文本块塑造一个最佳实践:仅在您有多行字符串时使用文本块;如果字符串适合单行代码(如前面的代码片段所示),则使用普通字符串字面量,因为使用文本块不会增加任何显著价值。
在捆绑的代码中,您可以在SQL、JSON和HTML的片段上实践本问题中的所有示例。
对于第三方库支持,请考虑:Apache Commons, StringUtils.join(), 和 Guava Joiner.on()。
接下来,让我们专注于处理文本块分隔符。
JavaScript 字符串用于存储和处理文本。
JavaScript 字符串
字符串可以存储一系列字符,如 "John Doe"。
字符串可以是插入到引号中的任何字符。你可以使用单引号或双引号:
实例
var carname="Volvo XC60";
var carname='Volvo XC60';
你可以使用索引位置来访问字符串中的每个字符:
实例
var character=carname[7];
字符串的索引从 0 开始,这意味着第一个字符索引值为 [0],第二个为 [1], 以此类推。
你可以在字符串中使用引号,字符串中的引号不要与字符串的引号相同:
实例
var answer="It's alright";
var answer="He is called 'Johnny'";
var answer='He is called "Johnny"';
你也可以在字符串添加转义字符来使用引号:
实例
var x='It\'s alright';
var y="He is called \"Johnny\"";
字符串长度
可以使用内置属性 length 来计算字符串的长度:
实例
var txt="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var sln=txt.length;
特殊字符
在 JavaScript 中,字符串写在单引号或双引号来中。
因为这样,以下实例 JavaScript 无法解析:x
"We are the so-called "Vikings" from the north."
字符串 "We are the so-called " 被截断。
如何解决以上的问题呢?可以使用反斜杠 (\) 来转义 "Vikings" 字符串中的双引号,如下:
"We are the so-called \"Vikings\" from the north."
反斜杠是一个转义字符。 转义字符将特殊字符转换为字符串字符:
转义字符 (\) 可以用于转义撇号,换行,引号,等其他特殊字符。
下表中列举了在字符串中可以使用转义字符转义的特殊字符:
代码 | 输出 |
---|---|
\' | 单引号 |
\" | 双引号 |
\ | 反斜杠 |
\n | 换行 |
\r | 回车 |
\t | tab(制表符) |
\b | 退格符 |
\f | 换页符 |
字符串可以是对象
通常, JavaScript 字符串是原始值,可以使用字符创建: var firstName="John"
但我们也可以使用 new 关键字将字符串定义为一个对象: var firstName=new String("John")
实例
var x="John";
var y=new String("John");
typeof x // 返回 String
typeof y // 返回 Object
不要创建 String 对象。它会拖慢执行速度,并可能产生其他副作用: |
实例
var x="John";
var y=new String("John");
(x===y) // 结果为 false,因为是字符串,y 是对象
===为绝对相等,即数据类型与值都必须相等。
字符串属性和方法
原始值字符串,如 "John", 没有属性和方法(因为他们不是对象)。
原始值可以使用 JavaScript 的属性和方法,因为 JavaScript 在执行方法和属性时可以把原始值当作对象。
字符串属性
属性 | 描述 |
---|---|
constructor | 返回创建字符串属性的函数 |
length | 返回字符串的长度 |
prototype | 允许您向对象添加属性和方法 |
字符串方法
Method | 描述 |
---|---|
charAt() | 返回指定索引位置的字符 |
charCodeAt() | 返回指定索引位置字符的 Unicode 值 |
concat() | 连接两个或多个字符串,返回连接后的字符串 |
fromCharCode() | 将 Unicode 转换为字符串 |
indexOf() | 返回字符串中检索指定字符第一次出现的位置 |
lastIndexOf() | 返回字符串中检索指定字符最后一次出现的位置 |
localeCompare() | 用本地特定的顺序来比较两个字符串 |
match() | 找到一个或多个正则表达式的匹配 |
replace() | 替换与正则表达式匹配的子串 |
search() | 检索与正则表达式相匹配的值 |
slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分 |
split() | 把字符串分割为子字符串数组 |
substr() | 从起始索引号提取字符串中指定数目的字符 |
substring() | 提取字符串中两个指定的索引号之间的字符 |
toLocaleLowerCase() | 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射 |
toLocaleUpperCase() | 根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射 |
toLowerCase() | 把字符串转换为小写 |
toString() | 返回字符串对象值 |
toUpperCase() | 把字符串转换为大写 |
trim() | 移除字符串首尾空白 |
valueOf() | 返回某个字符串对象的原始值 |
如您还有不明白的可以在下面与我留言或是与我探讨QQ群308855039,我们一起飞!
*请认真填写需求信息,我们会在24小时内与您取得联系。