一、API
1.什么是API
应用程序编程接口(已编写好的东西,直接使用)
2.Java中的API
指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来
如:Scanner,Random等
二、字符串
1.Stirng
java.lang.Stirng类代表字符串
字符串的内容不会发生改变,对象创建后不能被改变
Java中所有字符串文字都被视为此类的对象
(1)两种创建方式
1)直接赋值:Stirng name = “王一博”;
2)new:
方法名 | 说明 |
---|---|
public String() | 创建一个空白字符串对象,不含有任何内容 |
public String(char[] chs) | 根据字符数组的内容,来创建字符串对象 |
public String(byte[] bys) | 根据字节数组的内容,来创建字符串对象 |
(2)对字符串的“修改”
1)
//传递字符数组
//需求:修改字符串的内容
//abc-->{'a','b','c'}字符串不能修改,但数组可以修改,通过修改数组,实现字符串的“修改”
char[] chs = {'a','b','c'};
String s4 = new String(chs);
System.out.println(s4);
2)传递一个字节数组,根据字节数组内容再创建一个新的字符串对象
//需求:网络场景中传输数据都是字节信息
//一般把字节信息进行转换,转成字符,此时可以用到这个结构
byte[] bytes = {97,98,99,100};
String s5 = new String(bytes);
System.out.println(s5);//abcd
(3)Java的内存模型
1)栈内存:方法运行时进栈执行出栈结束
2)堆内存:new出来的对象都在这里
3)方法区:字节码文件(.class)临时存储
4)StringTable(串池):直接赋值的字符串存储在此;如果是new出来的,不在这里面。jdk7以后再堆内存里。
(4)两种创建方式的区别
public class StringDemo{
public static void main(){
String s1 = "abc";
String s2 = "abc";
}
}
步骤:
执行main方法,加载到栈内存中。执行程序,在栈内存创建s1,然后观察串池,串池里面有没有“abc”,如果没有创建,将地址返回给栈内存里的s1。如果已创建,直接将地址赋给s2.
public class StringDemo{
public static void main(){
char[] chs = {'a','b','c'};
String s1 = new Stirng(chs);
String s2 = new Stirng(chs);
}
}
步骤:
首先执行main方法,加载到栈内存中。执行程序,在栈内存创建chs。在堆内存中开辟空间存储数组{‘a’,‘b’,‘c’},然后将地址返回给chs。栈内存创建s1,在堆内存中开辟一小段新空间,存储“abc”,将其地址赋值给s1.创建s2,将上述过程重复一次,这个过程在堆内存里一共开辟了三小段空间,s1,s2存储的地址值并不一样。
综上:第一种比第二种更加简单,而且节约内存
(5)Java常用方法
1)==号比较
==号比什么?
基本数据类型:比的是具体的数据值
引用数据类型:比较的是地址值
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2)//true
分析:s1和s2存储的地址值,均为串池中“abc”的地址。
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2)//false
分析:s1记录的是堆里面的地址值,s2记录的是串池里的地址值
//1.键盘录入一个abc
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str1 = sc.next();
//2.代码中定义一个字符串abc
String str2 = "abc";
//3.用==比较,两者一样吗?
System.out.println(str1 == str2);//false
<1>equals方法的作用(完全一样,不能忽略大小写)
boolean equals(字符串)
<2>equalslgnoreCase(忽略大小写)
boolean equalslgnoreCase(字符串)
两者区别:是否忽略大小写
案例一:遍历字符串
public char charAt(int index)//根据索引返回字符
public int length()//返回字符串长度
//字符串长度:字符串对象.length()
//数组长度:数组名.length
案例二:金额转换
思想:反向逆推法
2135------>零佰零拾零万贰仟壹佰叁拾伍元
逆推:
零佰零拾零万贰仟壹佰叁拾伍元 —>零零零贰壹叁伍–>贰壹叁伍—>2135
数组索引:0~9
零 | 壹 | 贰 | 叁 | 肆 | 伍 | 陆 | 柒 | 捌 | 玖 |
---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数字当作索引去一一对应(查表法)
注意一:拼接的时候把要拼接的放到前面,避免结果反过来
moneyStr = capitalNumber+ moneyStr;
注意二:在最后输出结果时,对大写数字以及单位进行拼接
for (int i = 0; i < moneyStr.length(); i++) {
char c = moneyStr.charAt(i);
//把大写数字和单位拼接到result
result = result + c + arr[i];//arr存储的是单位,c时大写数字字符串的字符
}
案例三:手机号屏蔽
方法(包左不包右)
(1)
String substring(int beginIndex,int endIndex);//截取
只有返回值才是截取的小串
(2)
String substring(int beginIndex)
默认截取到末尾
案例四:身份证信息查看
String ch类型不能直接转为int,即使只有一个元素
先获取字符,ch.charAt(0),然后可以转化成int类型
案例五:敏感词替换
String replace(旧值,新值)//替换
只有返回值才是替换之后的结果
2.StringBuilder
(1)为什么学习它
字符串直接拼接100万次,速度非常慢
而用StringBuilder就会非常快
(2)概述
可以看作一个容器,创建之后内容可变
(3)两种方式拼接字符串
1)String
Sting s1 = "aaa";
Sting s2 = "bbb";
Sting s3 = "ccc";
Sting s4 = "ddd";
Sting s5 = "eee";
String s6 = s1 + s2 + s3 + s4 + s5;
过程:s1 与 s2 拼接,产生一个新的字符串,再与 s3 拼接,以此类推;在这个过程中,会产生许多没有用的字符串,浪费空间和时间
2)StringBuilder
这种方法,把s1,s2,s3,s4,s5全部放在StringBuilder容器里,在这个过程里,只有一个StringBuilder对象,效率更高
(4)常用方法
1)
public StringBuilder append(任意类型)
添加数据,并返回对象本身
2)
public StringBuilder reverse()
反转容器中的内容
3)
public int length()
返回长度(字符出现的个数)
4)
public String toString()
通过toString()可以实现把StringBuilder转换为String
(5)关于StringBuilder为空时
StringBuilder sb = new StringBuilder();
System.out.println(sb);
输出时什么都没有,因为StringBuilder是Java已经写好的类,Java底层对它做了一些处理,打印对象不是地址值而是属性值(即容器里的内容)。
(6)链式编程
当调用一个方法的时候,不需要用变量接收结果,可以继续调用其他方法
依赖前一个方法的结果再去调用其他的方法
sb.append("aaa");
sb.append("bbb");
sb.append("ccc");
sb.append("eee");
可以改写成下列形式
sb.append("aaa").append("bbb").append("ccc").append("eee");
3.StringJoiner
(1)为什么学习他
虽然StringBiulder速度快,但是有时候在使用时没那么方便。StringJoiner可以指定开始,结束,中间间隔等,更加方便
(2)概述
与StringBuilder一样,也可以看作是一个容器,创建后里面的内容是可变的。
代码编写简介,目前市场上很少有人用(JDK8出现的)
(3)构造方法
1)
public StringJoiner(间隔符号);//创建一个StringJoiner对象,指定拼接式的间隔符号
2)
public StringJoiner(间隔符号,开始符号,结束符号);
(4)成员方法
1)添加数据,并返回对象本身
public StringJoiner add(添加内容);//添加内容只能是字符串
2)返回长度
public int length();
例如 [a,b,c],长度要把" [ " , " , " , " ]"这三个字符算进来,长度为7
3)返回一个字符串(该字符串是拼接后的结果)
public String toString();
4.字符串原理(总结)
(1)字符串存储的内存原理
1)直接赋值会复用字符串常量池中的
2)new出来不会复用,而是开辟一个新的空间
(2)==号比较
1)基本数据类型比较数据值
2)引用数据类型比较地址值
(3)字符串拼接的底层原理
1)等号的右边没有变量(简单)
触发字符串的优化机制,在编译时已经是最终结果了
Java文件—>class文件
2)等号的右边有变量
JDK8以前会使用StringBuilder
String s1 = "a";
String s2 = s1 + "b";
String s3 = s2 + "c";
System.out.println(s3);
过程:
<1> 堆内存的串池里生成”a“,栈内存里的s1存储a的地址值;
<2> 堆内存的串池里生成”b“,拼接时有变量的参与,先在堆内存里创建一个StringBuilder的对象,通过append()方法把s1和”b“丢放在StringBuilder对象当中,通过toString()方法把其变成字符串,赋给s2(在这个过程中会new一个String对象);
在上面的代码中,每执行一行,都会生成一个StringBuilder的对象,所以性能差。
JDK8以后字符串拼接底层原理
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = s1 + s2 + s3;
System.out.println(s4);
<1>先预估(预估需要时间)最终字符串的长度,并且创建一个数组;
<2>把s1,s2,s3存入数组,再把数组整体变成一个字符串;
综合
如果很多字符串变量拼接,不要直接 + 。在底层会创建多个对象,浪费时间,浪费性能
—>如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用串池中的字符串
—>如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存。
(4)StringBuilder提高效率原理图
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
sb.append("c");
System.out,println(sb);
<1>main方法进栈,在堆内存中开辟一段空间,返回地址值赋给栈内存中的sb;
<2>调用append()方法,把a,b,c 依次添加到StringBuilder中;
常见面试题
1.
String s1 = "abc";
String s2 = "ab";
String s3 = s2 + "c";
System.out.println(s1 == s3);
分析:
s1—>记录串池中的地址值
对于s3
—>在JDK8以前,系统的底层会自动创建一个StringBuilder对象,然后会调用append方法完成拼接;拼接后,再调用toString方法转化为String类型,而toString方法的底层时直接new了一个字符串对象;他会在堆内存中新开辟一小段空间,返回地址值赋给s3;s2和s3存储的时不同地址的地址值,因为比较时不等。
—>JDK8以后,系统会预估要字符串拼接之后的总大小,把要拼接的内容都放在数组中,此时产生一个新的字符串,也是new出来的。
2.
String s1 = "abc";
String s2 = "a" + "b" + "c";
System.out.println(s1 == s2);
分析:
s1—>记录串池中的地址值
s2—>编译时,将"a" + “b” + “c"拼接成"abc”(此时代码还没有运行)
运行时,复用串池中的字符串
总结
—>所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存。
(5)StringBuilder源码分析
容量与长度注意区分
当容量不够时,StringBuilder会扩展容量,扩容:老容量 * 2 + 2 = 34
当添加的内容超过了默认扩容的容量时(即34),就以实际需要的容量为准。
总结
1.默认创建一个容量16的字节数组
2.添加内容长度小于16,直接存
3.添加内容大于16会扩容(原来容量 x 2 +2)
4.当内容大与默认的扩容容量,以实际长度为准
5.练习
(1)调整字符串
修改字符串内容的方法
<1>截取:用subString进行截取,把左边的字符截取出来拼接到右侧去;
<2>数组:可以把字符串先变成字符数组,调整字符数组里的数据,最后把字符数组变成字符串。
String str = “abcd”;
char[] arr = str.toCharArray();//该方法把字符串变成一个字符型数组
(2)单词长度
给一个字符串,有若干单词组成,求出最后一个单词长度
思路:
倒着遍历字符串,遇到第一个空格停止,遍历的次数即最后一个单词的长度