【JavaSE 第十二天】
一、 API 的概念
应用程序编程接口:每一个技术,官方都会定义出许多的功能,开发人员可以直接拿来使用。 API 可以理解为已经开发好的类和方法.。 API 文档是我们开发的帮手。
二、 Object 类
Object 类:是所有类的父类,一切类都直接或者间接继承 Object 类,Object 类中的所有功能,子类都可以使用。
好处:只要是定义一个类,他就拥有自己的构造方法,并继承来自 Object 的 11 个方法。
class XX {} //拥有自己默认的构造方法,并继承来自 Object 的 11 个方法
- 原因:Object 类定义在了 java.lang 包上, lang 包是核心包,此包中的任何类,在使用的时候不需要 import 导入
Object 类的构造方法:Object();
但是第一行中不是super();
1. Object 类的本地方法
本地方法:方法的定义使用关键字,修饰符
native
,这个方法就是本地方法。
本地方法的特点:
- 方法没有方法体
- 这个方法是 C++ 语言编写的,Sun 公司不开源
- 方法运行的时候,是一个独立的内存 (本地方法栈)
- 作用:凡是遇到本地方法,方法的作用是和本机的操作系统交互
2. Object 类的方法 toString()
- 自己定义的类 Person类,默认继承 Object 类,Object 类已经定义了方法:
public String toString(); // 结果是字符串,就是对象内存地址
- 输出语句中
System.out.println(对象);
(默认)调用对象的toString();
方法
System.out.println(对象);
就相当于:System.out.println( 对象.toString() );
public class Person {
}
public static void main(String[] args) {
Person person=new Person();
// 调用 person 对象的方法 toString();
String s = person.toString();
// 打印出的是对象在内存中的 “地址”
System.out.println("s = " + s);
// 输出语句中必须(默认)调用对象的方法 toString();
System.out.println("person = " + person);
}
- toString 方法的结果,和开发没有任何的关系。 我们需要的是重写父类的方法
toString();
,建立我们对象自己的字符串表现形式
(1) 重写父类的方法 toString()
原本的父类写法为:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
重写:
public class Person {
private String name;
private int age;
public Person(){} // 无参构造器
// 有参构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 重写了父类的方法 toString()
* 返回字符串
* 重写方法目标 : 方法中,返回类中成员变量的值
*/
public String toString(){
return name + ":" + age;
}
}
3. Object 类的方法 equals()
Java 技术认为任何对象都具备比较性,Object 类定义了方法
equals();
,作用就是用来比较对象。方法结果是 boolean 值,对象相等就是 true
- 自己进行对象的比较
创建 Person 类:
public class Person {
}
调用并比较:
public class ObjectTest {
public static void main(String[] args) {
// 创建两个对象
Person p1=new Person();
Person p2=new Person();
// p1 和 p2 对象进行比较
boolean b=p1.equals(p2);
System.out.println(b);
}
}
- Object 类的方法源码: equals 部分
public boolean equals(Object obj){
return (this == obj);
}
-
return (this == obj)
就是比较对象的地址(引用数据类型)是不是相同的 -
Object 类的方法
equals()
默认比较对象的内存地址
-
但是对象的地址不具有可比性,所以我们不能比较对象的地址,所以我们要重写
equals()
方法,建立我们创建的对象的自己的比较方式
建立我们对象 Person 自己的比较形式
重写 equals 方法:
创建 Person 类:
public class Person {
private String name;
private int age;
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 重写 equals 方法,建立 Person 对象自己的比较方式
* 比较对象的 age 年龄,年龄相同返回 true
*/
public boolean equals(Object obj){
// this 是调用者 p1 、 obj 是参数即比较的对象 p2
// this 就是指代 p1 、 obj 就是指代 p2
// 比较 this 对象的年龄 和 参数obj的年龄
// 一、健壮性判断的问题:如果 obj 对象的值是 null ,比较的另一个对象并不存在则直接返回 false 提高运行效率
if(obj==null){
return false;
}
// 存在多态的类型提升问题:对象 p2 是子类 但是 obj 是一个父类,如果传递进入 obj 就会出现类型提升问题(这是默认提升的),就不能调用子类特有的成员,所以要强制类型转换
// 要进行比较对象的年龄,只能将 obj 向下转型为 Person 类
// Person p=(Person)obj;
// return this.age==p.age;
// 但是此类操作存在安全隐患
// 二、判断 this 和 obj 是不是一个对象的问题:如果是直接返回 true 提高运行效率
// 怎么确定 this 和 obj 是不是一个对象:内存地址是否一样
if(this==obj){
return true;
}
// 三、必须事先判断 obj 是否是 Person 对象,才能够转换
if(obj instanceof Person){
// 判断 obj 是否是 Person 类的对象
Person p=(Person)obj;
return this.age==p.age;
}
// 如果不是 Person 类的对象则直接返回 false
return false;
}
}
调用:
class Cat{}
public class ObjectTest {
public static void main(String[] args) {
// 创建两个对象
Person p1=new Person("张三",5);
Person p2=new Person("李四",6);
// p1 和 p2 对象进行比较
boolean b1=p1.equals(new Cat());
System.out.println(b1);
boolean b2=p1.equals(p1);
System.out.println(b2);
boolean b3=p1.equals(p2);
System.out.println(b3);
}
}
三、 String 字符串类
字符串对象,程序中定义 " " 都是字符串对象,这个对象的使用频率最高。
字符串类: java.lang.String 类,继承自 Object 类,实现了三个接口。
程序中只要写 “…” 都是 String 类的对象。
字符串对象是常量,一旦创建不能修改。(为了线程安全)
1. 字符串对象的创建
public static void main(String[] args) {
// 字符串创建方式,共有两种:
// 1.直接创建的方式
String s="直接创建的方式";
// 2.使用构造方法创建的方式
String str="使用构造方法创建的方式";
// 因为原 String 类中具有这种自带的构造方法
}
- 直接创建的方式,代码少,书写简单,推荐使用
new String()
方式,使用了构造方法的创建形式,代码量大,不推荐使用
2. 字符串的实现原理
字符串这个数据类型,在 Java 中是不存在的,字符串的实现原理是用
char[]
数组表示。
例如:“abc”,这个字符串是使用数组char[] ch = {'a','b','c'} ;
以这种形式来表示
JDK9 版本之后,为了节约内存,从 char 数组 改变为了 byte 数组
JDK8 版本以前都是 char 数组
private final char value[]; // JDK 中 String 类型的源码表现
- 数组的前面的修饰符 final,使它成为最终的数组,数组一旦建立,数组的地址就被锁死(常量)。使用常量的原因:是为了线程安全
数组被 private 修饰,是私有的,并且类中其中并不提供 get/set 方法,无法改动
字符串的不变性解释:
public static void main(String[] args) {
// 字符串的不变性解释:
// abc 的内存地址是不会改变的
String s="abc";
System.out.println("s = " + s);
// 变量 s ,指向了新的字符串对象,其实是 s 的引用地址发生了变化
s="bbc";
// abc 和 bbc 在根本上是不会发生改变的,仍在那一块地址内存中
System.out.println("s = " + s);
// 类似于: int a=1; a=2; 1 和 2 本身不会变化,只是 a 被赋予的值变化
}
3. 字符串创建对象的区别
两种创建方式,并没有任何区别。
// 第一种:
String str = "abc";
// 第二种:
String str = new String("abc");
两种操作中内存中的运行状态完全相同。
内存分析的示例体会:
public class StringTest {
public static void main(String[] args) {
// 第一种情况:
String s1="abc";
String s2=new String("abc");
System.out.println(s1==s2); // 结果是 false 地址内存不同
// 第二种情况:
/**
* s3 ="hello" 内存中出现 String 对象,里面是 char 类型的数组
* s3 保存的是 String 对象
* s4 ="hello" 和 s3 中的字符串在内存中的数组表现是一样的
* 所以就会共用
* 导致 s3 的内存地址,赋值给 s4
*/
String s3="hello";
String s4="hello";
System.out.println(s3==s4); // 结果是 true
// 第三种情况:
/**
* s7 == (s5+s6) s5 和 s6 是变量
* 变量在编译的时候,javac 不确定变量的计算结果是什么
* 运行的时候,JVM 会为 s5+s6 的结果,新开内存空间
*/
String s5="ni";
String s6="hao";
String s7="nihao";
System.out.println(s7==(s5+s6)); // 结果是 false
// 第四种情况:
/**
* "how"+"you" 是常量,值 在编译期间就已经确定
* 运行的时候,不会建立新的内存空间
*/
System.out.println(s7==("ni"+"hao")); //结果是 true
/**
* 变量在编译时编译器不知道是什么值,并不确定
* 常量在编译时编译器已经确定了,直接编译为常量
*/
// 第五种情况:
String s8="a"+"b"+"c";
// 编译时直接编译为 "abc" 所以只创建了一个对象
}
public static void print(){
// abc 的内存地址是不会改变的
String s="abc";
System.out.println("s = " + s);
// 变量 s ,指向了新的字符串对象,其实是 s 的引用地址发生了变化
s="bbc";
// abc 和 bbc 在根本上是不会发生改变的,仍在那一块地址内存中
System.out.println("s = " + s);
// 类似于: int a=1; a=2; 1 和 2 本身不会变化,只是 a 被赋予的值变化
}
}
4. String 类的构造方法
(1) 字节编码
- 字符编码:ASCII, 小写字母 a 的值97,大写字母 A 的值是65,数字是48到57
ASCII 是美国标准信息交换代码,一个字节编码代表一个字符 - 中国(GB2312(大约4000个汉字)、GBK(大约20000个汉字,还有少数民族语言)、GB18030(尚未启用)),简体中文的编码表,汉字是用两个字节编码代表,并且两个字节编码都是负数的形式,防止与 ASCII 冲突
- ISO 国际标准化组织:全球的语言放在一个编码表中,万国语言标准:Unicode
UTF-8 :存储全球的文字(字节表示变长,但是能用一个字节表示的,绝不用两个字节表示,为了节省资源),在其中汉字用三个字节表示且都是负值
UTF-16 :定长表示,无论什么字符全部都是两个字节存储
(2) 常用的 String 类的构造方法
① 字节数组转成字符串
String(byte[] b)
字节数组转成字符串,使用平台的默认字符集String(byte[] b,int off,int len)
字节数组转成字符串,使用平台的默认字符集,参数 off 指的是:数组的开始索引,len 指的是:要转的个数String(byte[] b,int off,int len,String charsetName)
字节数组转成字符串,使用平台的默认字符集,参数 off 指的是:数组的开始索引,len 指的是:要转的个数,charsetName 参数是自己可以指定编码表
使用:
import java.io.UnsupportedEncodingException;
public class StringTest {
public static void main(String[] args) throws UnsupportedEncodingException {
stringConsByte3();
}
// 1.String 类构造方法相关:和字节相关
public static void stringConsByte(){
// String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
// 平台是操作系统,Windows 的默认字符集是 GBK
byte[] bytes = {97,98,99,100}; // 必须在 byte 的字节限制范围内
String str = new String(bytes);
System.out.println(str);
// 数组的一部分转成字符串
String str1 = new String(bytes,1,2); // 表示从1索引开始,要2个 写多了就会出现越界异常
System.out.println(str1);
}
// 2.String 类构造方法相关:和汉字相关
public static void stringConsByte2(){
// String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
// 原本 Windows 的默认字符集是 GBK
// 但是 IDEA 启动的时候,为 JVM 添加启动参数,默认字符集改成 UTF-8
byte[] bytes ={-28, -67, -96, -27, -91, -67}; // 在 UTF-8 中,6字节的数组,转为字符串后是2个汉字
String str = new String(bytes);
System.out.println(str);
String str1=new String(bytes,0,3); // 准确选择几个,否则汉字出不来
System.out.println(str1);
}
// 3.String 类构造方法相关:和字节、汉字相关
public static void stringConsByte3() throws UnsupportedEncodingException {
// String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
// Windows 的默认字符集是 GBK
// 在 IDEA 中强制指定为 GBK 编码
byte[] bytes ={-28, -67, -96, -27};
String str = new String(bytes,"GBK");
System.out.println(str);
}
}
② 字符数组转成字符串
String(char[] b)
字符数组转成字符串String(char[] b,int off,int len)
字符数组转成字符串,参数 off 数组的开始索引,len 要转的个数
与编码表无关
public static void main(String[] args) {
stringConsChar();
}
// String 类的构造方法,new String(char[])
public static void stringConsChar(){
char[] ch={'a','b','c','d','e'};
// 通过构造方法,数组转成字符串
String s = new String(ch);
System.out.println("s = " + s);
// 通过构造方法,数组转成字符串,转一部分
String s1 = new String(ch,1,3); // 从索引一开始,转三个
System.out.println("s1 = " + s1);
}
5. String 类的常用方法
(1) String 类的判断类型的方法,返回的都是布尔类型
boolean equals(Object obj)
字符串之间的比较,两个字符串相同,返回 true,严格区分大小写boolean equalsIgnoreCase(String str )
字符串之间的比较,两个字符串相同,返回 true,忽略大小写boolean startWith(String str)
判断字符串是否以另一个字符串开头,是开头就返回 true,严格区分大小写boolean endsWith(String str)
判断字符串是否以另一个字符串结尾,是结尾就返回 true,严格区分大小写boolean contains(String str)
判断字符串中是否包含另一个字符串,完全包含返回 true,严格区分大小写boolean isEmpty()
判断字符串的长度是不是0,如果是0返回 true
测试:
public static void main(String[] args) {
stringMethod();
}
/**
* String 类的判断方法
*/
public static void stringMethod(){
// 1. boolean equals(Object obj) 字符串之间的比较,两个字符串相同,返回 true
// String 类继承 Object,重写父类方法,原本比较的是字符串地址,但是重写之后就是比较字符串的实际内容是什么,严格区分大小写
String s1=new String("abc");
String s2=new String("abc");
boolean b=s1.equals(s2);
System.out.println("b = " + b);
// 2. boolean equalsIgnoreCase(String str ) 字符串之间的比较,两个字符串相同,返回 true,忽略大小写
// 简化写法:
b="abcde".equalsIgnoreCase("ABCDE");
System.out.println("b = " + b);
// 3. boolean startWith(String str) 判断字符串是否以另一个字符串开头,是开头就返回 true,严格区分大小写
// boolean endsWith(String str) 判断字符串是否以另一个字符串结尾,是结尾就返回 true,严格区分大小写
b="HelloWorld".startsWith("Hello");
System.out.println("b = " + b);
b="HelloWorld".endsWith("World");
System.out.println("b = " + b);
// 4. boolean contains(String str) 判断字符串中是否包含另一个字符串,完全包含返回 true,严格区分大小写
b="how are you".contains("are"); // true
b="how are you".contains("era"); // false
System.out.println("b = " + b);
// 5. boolean isEmpty() 判断字符串的长度是不是0,如果是0返回 true
b="".isEmpty();
System.out.println("b = " + b);
}
(2) String 类的获取方法,返回值不一定(有可能找得到,有可能找不到,有可能有多个,有可能没有)
int length()
返回字符串长度,字符串中字符的个数char charAt(int index)
返回指定索引上的单个字符int indexOf(String str)
返回指定的字符串,在当前字符串中第一次出现的索引int lastIndexOf(String str)
返回指定的字符串,在当前字符串中最后一次出现的索引String substring(int start,int end)
截取字符串,参数表示开始索引和结束索引,包含开头索引,不包含结束索引
public static void main(String[] args) {
stringMethod();
}
/**
* String 类的获取方法
*/
public static void stringMethod(){
// 1.int length() 返回字符串长度,字符串中字符的个数
int length="abcdef".length();
System.out.println("length = " + length);
// 2.char charAt(int index) 返回指定索引上的单个字符
char ch="abcdef".charAt(3); // 结果是 d 输入的参数超过了原限制就会发生越界异常
System.out.println("ch = " + ch);
// 3.int indexOf(String str) 返回指定的字符串,在当前字符串中第一次出现的索引
// 找不到指定的字符串,就返回 -1 ,因为负数不能作为索引出现
int index="how do you do".indexOf("d");
System.out.println("index = " + index);
// 4.int lastIndexOf(String str) 返回指定的字符串,在当前字符串中最后一次出现的索引
int last="how do you do".lastIndexOf(" ");
System.out.println("last = " + last);
// 5.String substring(int start,int end) 截取字符串,参数表示开始索引和结束索引,包含开头索引,不包含结束索引
String str="HelloWorld";
str = str.substring(2,6); // str.substring(2,6); 直接这样不赋值打印就会出现:"HelloWorld",因为它的值是锁死的,截取需要给变量重新赋值才能打印出来截取的值
System.out.println("str = " + str);
String str2="HelloWorld";
str2=str2.substring(0,str2.length()); // 这是截取全部
System.out.println("str = " + str2);
// substring 这个方法具有重载方法
String str1="你好我好大家好";
str1=str1.substring(3); // 从索引3开始,截取到最后
System.out.println("str1 = " + str1);
String str3="你好我好大家好";
str3=str3.substring(0);
System.out.println("str1 = " + str3); // 这也是截取全部
}
(3) String 类的转换方法
String toLowerCase()
字符串中的所有内容转成小写String toUpperCase()
字符串中的所有内容转成大写char[] toCharArray()
字符串转成字符数组byte[] getBytes()
字符串转成字节数组 (查询编码表),平台默认字符集byte[] getBytes(String charsetName)
字符串转成字节数组 (查询编码表),指定编码表static String valueOf(任意类型参数)
参数转成字符串对象
public static void main(String[] args) throws UnsupportedEncodingException {
stringMethod();
}
/**
* String 类的转换方法
*/
public static void stringMethod() throws UnsupportedEncodingException {
// 1.String toLowerCase() 字符串中的所有内容转成小写
// 2.String toUpperCase() 字符串中的所有内容转成大写
String str = "abCDefGHJktyM";
String lower = str.toLowerCase();
String upper = str.toUpperCase();
System.out.println("lower = " + lower);
System.out.println("upper = " + upper);
// 3.char[] toCharArray() 字符串转成字符数组
char[] ch = str.toCharArray();
System.out.println(ch);
// 4.byte[] getBytes() 字符串转成字节数组 (查询编码表),平台(操作系统)默认字符集
String s = "呵呵你好";
byte[] bytes = s.getBytes("gbk");
for (int i = 0; i < bytes.length; i++) {
System.out.println(bytes[i]);
}
// 5.static String valueOf(任意类型参数) 参数转成字符串对象
int i = 1;
String strI = String.valueOf(i);
System.out.println(strI+1);
}
(4) String 类的比较方法
int compareTo(String str)
字符串之间的比较,谁大谁小,按照字典顺序(自然顺序)(也就是 abcde… 的顺序)
public static void main(String[] args) {
stringMethod();
}
/**
* String 类的字符串的比较方法,字典顺序
*/
public static void stringMethod(){
// int compareTo(String str) 字符串之间的比较,谁大谁小,按照字典顺序(自然顺序)(也就是 abcde... 的顺序)
String str1="abc";
String str2="bbc";
// 对象 str1 调用方法 compareTo 参数传递 str2
/**
* 返回值是 int
* 返回的是负数,调用者小
* 返回的是整数,调用者大
* 返回的数零,就两者相等
* 从前往后比较一旦比出大小就不再向后进行
*/
int i=str1.compareTo(str2);
System.out.println("i = " + i);
}
(5) String 类的方法:去空格、替换、切割
String trim()
去掉字符串两边空格,中间空格不去掉String replace(String oldString,String newString)
替换字符串String[] split("规则字符串")
对字符串进行切割
public static void main(String[] args) {
stringMethod();
}
/**
* String类的方法 去空格,替换,切割
*/
public static void stringMethod() {
// 1. String trim() 去掉字符串两边空格,中间空格不去掉
String str = " abc def ";
System.out.println(str);
str = str.trim();
System.out.println("str = " + str);
// 2. String[] split("规则字符串") 对字符串进行切割
String splitStr = "aa,bb,cc,dd,ee"; // 以逗号进行切割
String[] strs = splitStr.split(","); // 需要有字符串数组接收切割后的数据
for (int i = 0; i < strs.length; i++) { // 遍历打印字符串数组
System.out.println(strs[i]);
}
// 3. String replace(String oldString,String newString)替换字符串
String repStr = "how do you do";
repStr = repStr.replace("o","N");
System.out.println("repStr = " + repStr);
}
(6) String 类正则表达式相关的功能
正则表达式 : 专门用于处理字符串的技术(应用广泛)
-
字符类 :
[abc]
字符串的这个位置只能是 abc[^abc]
字符串的这个位置不能是 abc[a-zA-Z]
字符串的这个位置必须是字母,52个[^a-zA-Z]
字符串的这个位置必须不能是字母,52个
-
数字类:
[0-9]
字符串的这个位置只能是数字[^0-9]
字符串的这个位置不能是数字[\d]
等同于[0-9]
[\D]
等同于[^0-9]
-
预定义字符 :
.
匹配所有的字符[\d]
等同于[0-9]
[\D]
等同于[^0-9]
[\w]
文字字符,包含数字、字母、下划线 等同于[a-zA-Z0-9_]
[\W]
文字字符,不能包含数字、字母、下划线 等同于[^a-zA-Z0-9_]
-
数量词 :
X{m}
X这个字符只能出现 m 次a{3}
表示 a 只能出现3次X{m,}
X这个字符至少出现 m 次X{m,n}
X这个字符至少出现 m 次,不超过 n 次X?
X这个字符出现一次,或者一次也没有X*
X这个字符出现零次或者多次X+
X这个字符出现至少一次
查阅 API 文档寻找更多用法
(7) 正则表达式的匹配功能:String 类的方法 matches()
public static void main(String[] args) {
stringMethod();
}
/**
* 正则表达式检查手机号码是否合法
* 开头必须是 1 ,长度固定为 11
* 第二位 3、4、5、6、7、8、9
* 第三位必须是数字
*/
public static void stringMethod(){
String tel="13800138000";
// 定义正则的规则,也是字符串
String regx="1[3-9][0-9]{9}";
// 第一位限制为 1 、第二位是 3-9 、第三位到最后一位都是数字 0-9 随机,一共出现九次
// 正则规则,和字符串校验
// String 类的方法 matches()
boolean matches=tel.matches(regx);
System.out.println("matches = " + matches);
}
public static void main(String[] args) {
stringMethod();
}
/**
* 检查邮箱
* 规则 :
* @ 字符 前面 : 可以是数组、字母、混合、下划线、位数先不限制
* @ 字符 后面 : 数组、字母、及 sina qq 126 1393 yahoo gmail 位数先不限制
* . 字符 固定 : com cn org edu gov 字母 位数放下
*/
public static void stringMethod(){
String email = "shihehe@sina.com";
String reg = "[\\w]+@[a-z0-9]+(\\.[a-z]+)+";
// 在 Java 中‘ \ ’有转义的功能,所以要多写一个
// 用小括号括起来就是一组,一组重复出现,设置次数,实际出现要小于等于设置的次数
boolean b = email.matches(reg);
System.out.println(b);
}
(8)String 类的方法 split()
(支持正则的切割)
public static void stringMethod(){
public static void main(String[] args) {
stringMethod();
}
String str = "as123d387654w5465fasfr234567sa";
String[] strings = str.split("\\d+"); // 按照数字切割 “ + ” 表示至少出现一次
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
String ip = "192.....168.....35.121";
String[] ipArray = ip.split("\\.+"); // 按照数字切割 “ . ” 表示至少出现一次
for (int i = 0; i < ipArray.length; i++) {
System.out.println(ipArray[i]);
}
}
(9)String 类的方法 replaceAll()
(支持正则的替换)
public static void stringMethod4(){
String str = "as123d387654w5465fasfr234567sa";
// 字符串中的所有数字,换成 #
String repString = str.replaceAll("\\d+","#"); // 定义新字符串,因为原字符串不能改动
System.out.println(repString);
// 只替换第一个符合规则的字符
String first = str.replaceFirst("\\d+","#");
System.out.println(first);
}
6. StringBuilder 字符串构建器
StringBuilder 是字符串对象的缓冲区对象,缓冲区(出现的目的,为了高效)提高 String 类的效率。
(1) 引出 StringBuilder 类
String str1 = "a"; // 字符数组
String str2 = "b"; // 字符数组
String str3 = str + str2; // 字符数组
这样写占用内存,字符串使用效率低,为了压缩内存出现了 StringBuilder 字符串构建器
(2) StringBuilder 类的实现原理
一个可变的字符序列,字符序列就是字符数组。
String 类中 : private final char[] value;
StringBuilder : char[] value; // 其中的方法是缺省状态只有本包可以使用,但是提供了 public 方法,可以调用
- 字符序列是数组,Java 数组是定长的,一旦创建,长度固定 。
- 创建对象的时候,StringBuilder 中的数组的初始化长度为16个字符
- 出现无法容纳问题的时候, StringBuilder 自动的进行数组的扩容,新创建一个数组,并且是开始数组的两倍,新数组实现,原来数组的中元素复制到新的数组,并且原数组被内存废弃销毁。
(复制数组也很耗资源,但是相对于多有很多数组内存来说,综合考虑 StringBuilder 类较好。)
-
结论 : 无论怎么做字符串的操作,StringBuilder 内部永远只有一个数组。
-
StringBuilder 类是线程不安全的类,运行速度快,推荐使用 StringBuilder 。
-
StringBuffer 是线程安全的类,运行速度慢,多线程的程序中使用。
这两个类的构造方法,和其他的方法都一模一样。