在Java编程语言中,字符(char)和字符串(String)是两种截然不同的数据类型。
字符类型
char
是一个基本数据类型,代表一个Unicode字符。
每个char
变量占用两个字节的内存空间,用于存储一个Unicode字符,无论是英文字母、数字还是中文汉字。
char c1 = 'A'; // 一个英文大写字母A
char c2 = '中'; // 一个中文汉字
可以通过将char
类型直接赋值给int
类型来获取其Unicode编码:
int n1 = 'A'; // A的Unicode编码是65
int n2 = '中'; // 中文汉字的Unicode编码是20013
也可以使用Unicode编码的十六进制表示来创建字符:
char c3 = '\u0041'; // 'A'的Unicode编码
char c4 = '\u4e2d'; // '中'的Unicode编码
字符串类型
String
是一个引用类型,用于表示和操作一系列字符。
字符串由双引号"..."
包围,可以包含0个到任意数量的字符,包括空格。
String s = ""; // 空字符串
String s1 = "A"; // 单个字符
String s2 = "ABC"; // 多个字符
String s3 = "中文 ABC"; // 包含中文和空格的字符串
如果字符串中需要包含双引号,可以使用转义字符\
:
String s = "abc\"xyz"; // 包含双引号的字符串
转义字符\
也用于表示其他特殊字符,如:
String s = "abc\\xyz"; // 包含反斜杠的字符串
常见的转义字符还包括:
\"
:表示双引号字符"
\'
:表示单引号字符'
\n
:表示换行符\r
:表示回车符\t
:表示制表符(Tab)\u####
:表示Unicode编码的字符,其中####
是四位十六进制数。
例如,创建一个包含换行符和中文字符的字符串:
String s = "ABC\n\u4e2d\u6587"; // 包含换行符和中文字符“中文”
字符串连接
Java编译器提供了一种特殊的机制来处理字符串连接操作,使得我们可以方便地将字符串与其他类型的数据进行拼接。这种机制称为字符串拼接(String Concatenation)。
当我们使用加号(+
)来连接字符串时,如果操作数中包含非字符串类型的数据,Java会自动将这些数据转换为字符串类型,然后再进行拼接。这个过程称为字符串的自动装箱(autoboxing)和字符串的转换。
以下是一个字符串拼接的例子:
public class Main {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "world";
// 使用加号连接字符串
String s = s1 + " " + s2 + "!";
System.out.println(s); // 输出:Hello world!
}
}
在这个例子中,s1
和s2
都是字符串类型,它们可以直接使用+
进行拼接。拼接的结果也是一个字符串。
另一个例子展示了如何将字符串与其他数据类型拼接:
public class Main {
public static void main(String[] args) {
int age = 25;
// 将整数转换为字符串,然后与字符串拼接
String s = "age is " + age;
System.out.println(s); // 输出:age is 25
}
}
多行字符串
在Java 13及以后的版本中,引入了多行字符串(Text Blocks)的功能,这使得创建跨越多行的字符串变得更加方便和直观。多行字符串使用三个双引号"""...""""
来界定,而不是使用加号(+
)来连接字符串。
以下是一个使用多行字符串的例子:
public class Main {
public static void main(String[] args) {
// 使用多行字符串
String s = """
SELECT * FROM
users
WHERE id > 100
ORDER BY name DESC
""";
System.out.println(s);
}
}
在这个例子中,多行字符串包含了SQL查询语句,它自动保留了换行符和空格,使得代码更加易读。
如果你不希望在多行字符串的末尾添加额外的换行符,可以这样写:
String s = """
SELECT * FROM
users
WHERE id > 100
ORDER BY name DESC
""";
多行字符串会自动去除每行开头的共同空格,只保留最短行首的空格。例如:
String s = """
...........SELECT * FROM
........... users
...........WHERE id > 100
...........ORDER BY name DESC
""";
在这个例子中,所有的空格都被去除了,只保留了最短行首的空格。
如果多行字符串的排版不规则,去除的空格会以最短的行首空格为基准:
String s = """
......... SELECT * FROM
......... users
.........WHERE id > 100
......... ORDER BY name DESC
""";
在这个例子中,由于第二行的空格比第一行和第三行多,所以去除空格后,所有行都会以第二行的空格数为基准。
不可变特性
Java中的字符串具有不可变性,这是一个核心特性。这意味着一旦字符串被创建,它的内容就不能被改变。这个特性对于字符串的操作和内存管理有着重要的影响。
在下面的代码示例中:
public class Main {
public static void main(String[] args) {
String s = "hello";
System.out.println(s); // 输出 "hello"
s = "world";
System.out.println(s); // 输出 "world"
}
}
虽然看起来变量s
的值从”hello”变为了”world”,但实际上,变量s
本身并没有直接改变字符串的内容。在Java中,字符串是存储在堆(heap)上的,而变量s
是一个引用,它指向堆上的字符串对象。
当执行String s = "hello";
时,Java虚拟机(JVM)首先在堆上创建了一个字符串对象”hello”,然后创建了一个名为s
的变量,并将这个变量的引用指向这个字符串对象。
随后,当执行s = "world";
时,JVM在堆上创建了一个新的字符串对象”world”,并将变量s
的引用更新为指向这个新的对象。原来的字符串对象”hello”仍然存在于堆上,但由于s
的引用已经指向了”world”,我们无法通过s
来访问”hello”了。这个过程并不是修改了原有的字符串,而是改变了引用的指向。
字符串的不可变性确保了字符串对象在创建后,其内容始终保持不变。这对于字符串的安全性和性能优化非常重要,因为它允许Java在编译时对字符串进行优化,比如字符串常量池的使用,以及在运行时避免不必要的字符串复制。
空值null
在Java中,引用类型的变量可以被赋予一个特殊的值null
,这个值用来表示该变量当前不指向任何对象。null
是一个空引用,它没有指向任何内存地址,因此它不关联任何对象实例。
以下是一个示例来说明null
和空字符串(””)之间的区别:
String s1 = null; // s1是一个空引用,它不指向任何字符串对象
String s2 = s1; // s2也变成了空引用,它同样不指向任何字符串对象
String s3 = ""; // s3指向一个空字符串,这是一个有效的字符串对象,内容为空
在这个例子中,s1
和s2
都被赋予了null
,这意味着它们都是空引用,不指向任何字符串对象。而s3
被赋予了一个空字符串(””),这是一个长度为0的字符串对象,它是存在的,并且有实际的内容(即没有字符)。
需要注意的是,null
和空字符串(””)在Java中被视为不同的值。尽管它们都表示没有内容,但它们在类型和用途上有所不同。null
是一个表示“无”或“不存在”的特殊值,而空字符串是一个实际的对象,它存在于内存中,并且可以被操作和修改。
在编程实践中,正确理解和使用null
和空字符串是非常重要的,因为它们在逻辑处理和异常处理中扮演着关键角色。例如,尝试访问一个null
引用的属性或方法会导致NullPointerException
,而对空字符串进行操作则不会。