Java 中的 String 属于引用类型,它是一个类,这和其他语言是不一样的。

一、String 对象的创建方式

我们先看创建 String 对象的两种方式。

1、通过字符串常量的方式

String str = "Deepspace";

2、String() 构造函数的方式

String str = new String("Deepspace");

这两种创建的方式是有区别的,这里先暂时不讲,等我们熟悉了 String 对象的操作之后,再来看它们的区别。

二、String 对象的不可变性

我们都知道了 String 对象是不可变的。那它不可变是怎么做到的呢?Java 这么做能带来哪些好处?

1、为什么不可变?

先来看看 String 对象的一段源码:

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/*** use serialVersionUID from JDK 1.0.2 for interoperability*/private static final long serialVersionUID = -6849794470754667710L;/*** 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 类是被 final 修饰的,也即意味着 String 类不能被继承,并且它的成员方法都默认为 final 方法,这是 String 对象不可变的第一点;
  • String 类其实是通过 char 数组来保存字符串的,也是使用 private final 来声明的,我们知道对于一个被 final 修饰符修饰的基本数据类型的变量,其值一旦被初始化之后就不能再更改了,这是 String 对象不可变的第二点。

2、不可变有什么好处

JavaString 对象设计成不可变的,有什么好处呢?主要有下面三个好处:

  • 保证 String 对象的安全性;假设 String 对象是可变的,那么 String 对象将可能被恶意修改;

  • 可以实现字符串常量池;

    我们知道,字符串的分配,和其他的对象分配一样,会耗费时间与内存空间;作为最基础的数据类型,如果大量且频繁地创建字符串,会极大程度地影响程序的性能。所以,JVM 为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化,优化思想是这样的:

    为字符串开辟一个字符串常量池,类似于缓存区;创建字符串常量时,首先检查字符串常量池是否存在该字符串;如果存在该字符串,就返回引用实例,如果不存在,则实例化该字符串并放入池中。

    所以,我们可以肯定的是:常量池中一定不存在两个相同的字符串。

  • 加快字符串处理速度。

    因为字符串是不可变的,所以在它创建的时候, hashcode 就被缓存了,不需要重新计算。这就使得字符串很适合作为 Map 中的键,字符串的处理速度要快过其它的键对象。这就是 HashMap 中的键往往都使用字符串的原因。

下面再看看 String 类的一些方法实现:

public String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}int len = value.length;char buf[] = Arrays.copyOf(value, len + otherLen);str.getChars(buf, len);return new String(buf, true);
}public String replace(char oldChar, char newChar) {if (oldChar != newChar) {int len = value.length;int i = -1;char[] val = value; /* avoid getfield opcode */while (++i < len) {if (val[i] == oldChar) {break;}}if (i < len) {char buf[] = new char[len];for (int j = 0; j < i; j++) {buf[j] = val[j];}while (i < len) {char c = val[i];buf[i] = (c == oldChar) ? newChar : c;i++;}return new String(buf, true);}}return this;
}// ...

String 类里的一些方法实现可以看出,无论是 concat 操作还是 replace 操作,都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

三、String 的常见操作

1、字符串的比较

字符串比较是常见的操作,包括比较相等、比较大小、比较前缀和后缀串等。

我们经常使用 == 运算符比较的是两个对象引用,看它们是否引用相同的实例。

String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2); // true

如果我们想比较两个字符串对象的内容,== 运算符就不再适用了。 Java 提供了一些方法用来比较字符串。

equals() 方法

equals() 方法将逐个地比较两个字符串的每个字符是否相同。如果两个字符串具有相同的字符和长度,它返回 true,否则返回 false。并且,对于字符的大小写,也在检查的范围之内。

String str1 = "abc";
String str2 = new String("abc");
String str3 = "ABC";
System.out.println(str1.equals(str2)); // true
System.out.println(str1.equals(str3)); // false

equalsIgnoreCase() 方法

equalsIgnoreCase() 方法的作用和语法与 equals() 方法完全相同,唯一不同的是 equalsIgnoreCase() 在比较时不区分大小写。当比较两个字符串时,它会认为 A-Za-z 是一样的。

String str1 = "abc";
String str2 = "ABC";
System.out.println(str1.equalsIgnoreCase(str2)); // true

compareTo() 方法

通常,仅仅知道两个字符串是否相同是不够的。对于排序应用来说,必须知道一个字符串是大于、等于还是小于另一个字符。

一个字符串小于另一个字符串指的是它在字典中先出现,大于则指的是它在字典中后出现。

compareTo() 方法实现了这种功能。compareTo() 方法用于按字典顺序比较两个字符串的大小,该比较是基于字符串各个字符的 Unicode 值。

String str = "A";
String str1 = "a";
System.out.println("str=" + str);
System.out.println("str1=" + str1);
System.out.println("str.compareTo(str1)的结果是:" + str.compareTo(str1));
System.out.println("str1.compareTo(str)的结果是:" + str1.compareTo(str));
System.out.println("str1.compareTo('a')的结果是:" + str1.compareTo("a"));

"A"Unicode 值为 0034"a"Unicode 值为 0066

所以输出结果为:

str=A
str1=a
str.compareTo(str1)的结果是:-32
str1.compareTo(str)的结果是:32
str1.compareTo('a')的结果是:0

注意:如果两个字符串调用 equals() 方法返回 true,那么调用 compareTo() 方法会返回 0

switch statement 中的比较

Java 1.7 版本之后,在 switch statement 中的比较,默认使用的是 equals() 方法。

String stringToSwitch = "A";
switch (stringToSwitch) {case "a":System.out.println("a");break;case "A":System.out.println("A"); // the code goes herebreak;case "B":System.out.println("B");break;default:break;
}

2、获取字符串的长度

String string = "This is a Random String";
System.out.println(string.length()); // 23

3、更改字符串中字符的大小写

toUpperCase 方法 和 toLowerCase 方法用于转换字符串中字符的大小写。

String string = "This is a Random String";
String upper = string.toUpperCase();
String lower = string.toLowerCase();
System.out.println(string); // "This is a Random String"
System.out.println(lower); // "this is a random string"
System.out.println(upper); // "THIS IS A RANDOM STRING"

4、截取(提取)子字符串

String 中提供了 substring() 方法用于截取字符串,它有两种形式:

  • 一个是从指定位置截取到字符串结尾:substring(int beginIndex) 形式;

  • 另一个是截取指定范围的内容:substring(int beginIndex,int endIndex) 形式。

public class Main {public static void main(String[] args) {String day = "Today is Monday";System.out.println("substring(0)结果:" + day.substring(0));System.out.println("substring(2)结果:" + day.substring(2));System.out.println("substring(10)结果:" + day.substring(10));System.out.println("substring(2,10)结果:" + day.substring(2, 10));System.out.println("substring(0,5)结果:" + day.substring(0, 5));}
}

输出结果为:

substring(0)结果:Today is Monday
substring(2)结果:day is Monday
substring(10)结果:onday
substring(2,10)结果:day is M
substring(0,5)结果:Today

5、去除字符串中的空格

trim() 方法用于去掉字符串中的首尾空格。

String str = " hello ";
System.out.println(str.length()); // 7
System.out.println(str.trim().length()); // 5

6、分割字符串

String 类的 split() 方法可以按指定的分割符对目标字符串进行分割,分割后的内容存放在字符串数组中。

public class Main {public static void main(String[] args) {String Colors = "Red,Black,White,Yellow,Blue";String[] arr1 = Colors.split(","); // 不限制元素个数String[] arr2 = Colors.split(",", 3); // 限制元素个数为3System.out.println("所有颜色为:");for (String s : arr1) {System.out.println(s);}System.out.println("前三个颜色为:");for (String s : arr2) {System.out.println(s);}}
}

输出结果为:

所有颜色为:
Red
Black
White
Yellow
Blue
前三个颜色为:
Red
Black
White,Yellow,Blue

7、字符串拼接

使用 + 号连接

public class Main {public static void main(String[] args) {String str = "Welcome to " + "Beijing" + "!";System.out.println(str);}
}

使用 concat() 方法

public class Main {public static void main(String[] args) {String book = "三国演义、";book = book.concat("西游记、");book = book.concat("水浒传、");book = book.concat("红楼梦");System.out.println(book); // 三国演义、西游记、水浒传、红楼梦}
}

连接其他类型的数据

前面的例子都是字符串与字符串进行连接,其实字符串也是可以同其他基本数据类型进行连接。如果将字符串同这些基本数据类型数据进行连接,此时会将这些数据直接转换成字符串。

public class Main {public static void main(String[] args) {String book = "三国演义"; // 字符串int price = 59; // 整型变量float readTime = 2.5f; // 浮点型变量System.out.println("我买了一本图书,名字是:" + book + "\n价格是:" + price + "\n我每天阅读" + readTime + "小时");}
}

上述代码实现的是将字符串变量 book 与整型变量 price 和浮点型变量 readTime 相连后将结果输出。在这里定义的 pricereadTime 都不是字符串,当它们与字符串相连时会自动调用自身的 toString() 方法将其转换成字符串形式,然后再参与连接运算。

输出结果为:

我买了一本图书,名字是:三国演义
价格是:59
我每天阅读2.5小时

8、查询字符串

我们经常会查找一个字符串中是否包含另一个字符串,Java 也提供了一些方法来处理。

contains() 方法

public class Main {public static void main(String[] args) {String str1 = "Hello World";String str2 = "Hello";String str3 = "helLO";System.out.println(str1.contains(str2)); // trueSystem.out.println(str1.contains(str3)); // false}
}

contains() 方法区分大小写。

indexOf() 方法

indexOf() 方法用于返回字符(串)在指定字符串中首次出现的索引位置,如果能找到,则返回索引值,否则返回 -1

public class Main {public static void main(String[] args) {String words = "today,monday,sunday";System.out.println(words.indexOf("day")); // 2System.out.println(words.indexOf("day", 5)); //9System.out.println(words.indexOf("o")); // 1System.out.println(words.indexOf("o", 6)); // 7System.out.println(words.indexOf("today")); // 0System.out.println(words.indexOf("z")); // -1}
}

indexOf() 方法返回索引,如果没找到,则返回 -1

lastlndexOf() 方法

lastIndexOf() 方法用于返回字符(串)在指定字符串中最后一次出现的索引位置,如果能找到则返回索引值,否则返回 -1

public class Main {public static void main(String[] args) {String words = "today,monday,Sunday";System.out.println(words.lastIndexOf("day")); // 16System.out.println(words.lastIndexOf("day", 5)); // 2System.out.println(words.lastIndexOf("o")); // 7System.out.println(words.lastIndexOf("o", 6)); // 1}
}

lastIndexOf() 方法的查找策略是从右往左查找,如果不指定起始索引,则默认从字符串的末尾开始查找。

charAt() 方法

charAt() 方法可以在字符串内根据指定的索引查找字符。

public class Main {public static void main(String[] args) {String words = "today,monday,sunday";System.out.println(words.charAt(0)); // tSystem.out.println(words.charAt(1)); // oSystem.out.println(words.charAt(8)); // n}
}

字符串本质上是字符数组,因此它也有索引,索引从零开始。

四、StringBuffer

通过前面的内容,我们知道了 String 对象不可变的特性,这在一些情况下会带来不便,如拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。

所以,Java 提供了两个可变字符串类 StringBufferStringBuilder,中文翻译为 “字符串缓冲区”

StringBuffer 就是为了解决大量拼接字符串时产生很多中间对象的问题而提供的一个类。使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。

每个 StringBuffer 类的对象都能够存储指定容量的字符串,如果字符串的长度超过了 StringBuffer 类对象的容量,则该对象的容量会自动扩大

1、创建 StringBuffer 类

StringBuffer 类提供了 3 个构造方法来创建一个字符串:

public class Main {public static void main(String[] args) {// 定义一个空的字符串缓冲区,含有16个字符的容量StringBuffer str1 = new StringBuffer();// 定义一个含有10个字符容量的字符串缓冲区StringBuffer str2 = new StringBuffer(10);// 定义一个含有(16+4)的字符串缓冲区,"Java"为4个字符StringBuffer str3 = new StringBuffer("Java");/**输出字符串的容量大小*capacity() 方法返回字符串的容量大小*/System.out.println(str1.capacity());  // 输出 16System.out.println(str2.capacity());  // 输出 10System.out.println(str3.capacity());  // 输出 20}
}

capacity() 方法返回 StringBuffer 对象字符串的容量大小。

2、追加字符

使用 append() 方法用于向原有 StringBuffer 对象中追加字符串。

public class Main {public static void main(String[] args) {String str = "study";str.concat("tonight");System.out.println(str); // studyStringBuffer strB = new StringBuffer("study");strB.append("tonight");strB.append("!");System.out.println(strB); // studytonight!}
}

也可以使用链式调用的方式来书写:

strB.append("tonight").append("!");

3、替换字符

setCharAt() 方法用于在字符串的指定索引位置替换一个字符。

public class Main {public static void main(String[] args) {StringBuffer sb = new StringBuffer("hello");sb.setCharAt(1, 'E');System.out.println(sb);    // hEllosb.setCharAt(0, 'H');System.out.println(sb);    // HEllosb.setCharAt(2, 'p');System.out.println(sb);    // HEplo}
}

也可以使用 replace() 方法来替换:

public class Main {public static void main(String[] args) {StringBuffer sb = new StringBuffer("hello java");sb.replace(1, 5, "tttt");System.out.println(sb); // htttt java}
}

4、反转字符串

reverse() 方法用于将字符串序列用其反转的形式取代。

public class Main {public static void main(String[] args) {StringBuffer sb = new StringBuffer("java");sb.reverse();System.out.println(sb); // avaj}
}

5、删除字符串

StringBuffer 类提供了 deleteCharAt()delete() 两个删除字符串的方法。

deleteCharAt() 方法的作用是删除指定位置的字符,然后将剩余的内容形成一个新的字符串:

StringBuffer sb = new StringBuffer("She");
sb.deleteCharAt(2);
System.out.println(sb); // Sh

delete() 方法用于删除指定区域以内的所有字符,语法是:

new StringBuffer().delete(int start,int end);

start 表示要删除字符的起始索引值(包括索引值所对应的字符),end 表示要删除字符串的结束索引值(不包括索引值所对应的字符)。

public class Main {public static void main(String[] args) {StringBuffer sb = new StringBuffer("hello java");sb.delete(2, 5);System.out.println(sb); // he javasb.delete(2, 5);System.out.println(sb); // heva}
}

6、插入数据

insert() 方法用于将数据插入 StringBuffer 对象中。

public class Main {public static void main(String[] args) {StringBuffer sb = new StringBuffer("hello java");sb.insert(3, "1234");System.out.println(sb); // hel1234lo java}
}

7、截取数据

substring() 方法可以截取 StringBuffer 对象,返回值不在是缓冲区本身,而是一个新的字符串

public class Main {public static void main(String[] args) {StringBuffer sb = new StringBuffer("hello java");String sb1;sb1 = sb.substring(1, 3);System.out.println(sb); // hello javaSystem.out.println(sb1); // el}
}

8、StringBuffer 与 String 的相互转化

public class Main {public static void main(String[] args) {String s1 = "java";System.out.println("String  " + s1); // String  java// 将string转成StringBufferStringBuffer s2 = new StringBuffer(s1);System.out.println("StringBuffer " + s1); // StringBuffer java// 将StringBuffer转成StringString s3 = s2.toString();System.out.println("String " + s3); // String java}
}

五、StringBuilder

在很多情况下,字符串拼接操作不需要线程安全,所以 StringBuilder 登场了。StringBuilder 是在 JDK1.5 中发布的,它和 StringBuffer 本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。所以,在没有线程安全的需求下,优先使用 StringBuilder

在方法的使用上面,StringBuilderStringBuffer 是一样的,这里就不再重复。

关于线程安全,会在后面讲到。

Java 中的 String、StringBuffer、StringBuilder相关推荐

  1. 重温java中的String,StringBuffer,StringBuilder类

    不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...

  2. Java中的String,StringBuffer,StringBuilder有什么区别?

    相信有很多同学都是经常使用String的,或者也或多或少的听说过StringBuffer,StringBuilder,那么在经常遇见的面试题中(标题),到底这三个的区别是什么呢?让我们来一探究竟! S ...

  3. Java:中的String,StringBuilder,StringBuffer三者的区别

    Java中的String,StringBuilder,StringBuffer三者的区别 最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBu ...

  4. Java中的String,StringBuilder,StringBuffer三者的区别

    最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...

  5. Java中的String、StringBuilder、StringBuffer

    Java中的String是个永恒的话题,直说我想说的. 1.String 是永远不会变的,传递的引用是一个Copy,无论刮风下雨,它都在自己的小窝里呆的好好的. 2.重载"+"和S ...

  6. Java中的String,StringBuilder,StringBuffer的区别

    这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > ...

  7. Java 中的 String、StringBuilder、StringBuffer 的区别

    目录 一.是什么? 二.区别是? 1. 运行速度(执行速度) 2. 线程安全 三.小结 四.加餐 一.是什么? String 不可变字符序列 String 是字符串常量,其对象一旦创建之后该对象是不可 ...

  8. 浅谈 Java 字符串(String, StringBuffer, StringBuilder)

    我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...

  9. 探秘Java中的String、StringBuilder以及StringBuffer

    转载:http://www.cnblogs.com/dolphin0520/p/3778589.html 一.你了解String类吗? 想要了解一个类,最好的办法就是看这个类的实现源代码,String ...

  10. 【转】探秘Java中的String、StringBuilder以及StringBuffer

    探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一 ...

最新文章

  1. 网站关键词优化首先要学会分类!
  2. 撰写第三周课程总结及实验报告(一)
  3. 字节、阿里等大厂的技术如何?看看这些Java程序员的自学笔记
  4. cdr放大后内容消失了_今日推荐:AI智能图片清晰放大神器强势来袭,简直无敌了...
  5. MongoDB - 分片管理
  6. 0基础如何系统的学习Python? 只要完成这 9 步
  7. OSPF特殊区域及LSA类型详解
  8. mysql基础知识理解和sql题讲解分析面试实战(四)之函数讲解和字符串的操作...
  9. 5. CopyOnWriteArrayList 的适用场景
  10. Restsharp 与 unity3D WWW
  11. mac-数据库建模工具Workbench、PDMan
  12. python cls方法_python – cls()函数在类方法中做了什么?
  13. Matlab|如何美化plot线条颜色
  14. H5--drag拖拽事件
  15. 8421 BCD码 加减校正
  16. 淘宝/天猫采集商家信息插件
  17. 2023.02.14草图大师 卧室房间 效果图
  18. 占位符语法-Scala
  19. Linux如何配置ssh key
  20. 如何点击验证码刷新验证码的问题解决方法?

热门文章

  1. 这样拆分和压缩css代码
  2. C++内置类型对象之间的隐式转换
  3. 展开式求和(c语言)
  4. java控制小数位数_java中怎么控制double的小数位数?
  5. mysql 1114错误_mysql – ERROR 1114(HY000):表’XXX’已满
  6. matlab 优化 小于,科学网—matlab全局优化与局部优化 - 张凌的博文
  7. Mysql从入门到入魔——5. 聚集、分组、子查询
  8. Levels - 虚幻引擎场景制作
  9. 【Questasim】报错001 Failed to access library
  10. app抓包服务器证书错误,Fiddler抓包iOS出现证书错误的解决办法