目录
- String
- 字符串拼接
- 字符串截取
- 与数字相接
- 不可变字符串
- 检测字符串是否相等
- 字符串常量池
- 空串和null串
- 码点与代码单元
- String API
- 字符串数组
- 构建字符串
- buffer机制
- String、StringBuilder、StringBuffer 区别
- 比特流、网络流、文件流
String
字符串拼接
除了基本类型都叫引用类型。
public class Test{
public static void main(String[] xxx){
String x1 = "abcdef";
String x2 = "12314";
System.out.println(x1 + x2);
}
}
引用类型同样类型的大小就不一样了。
任何引用类型都由基本类型组成。
字符串截取
public class Test{
public static void main(String[] xxx){
String x1 = "abcdef";
String x2 = "012314";
String x3 = x2.substring(2, 4);
System.out.println(x3);
}
}
substring(2,5); // [2, 4)
与数字相接
public class Test{
public static void main(String[] xxx){
String x1 = "abcdef";
String x2 = "012314";
String x3 = x2.substring(2, 4);
System.out.println(x3);
String x6 = "afd" + 33;
int a = 90;
float b= 234.34f;
String x7 = x6 + a + b;
System.out.println(x7);
}
}
不可变字符串
由于长度会发生改变,不能在原地修改,所以引用指向别的地方。
检测字符串是否相等
经常用C++的可能会使用 ==
而在java中 == 只能判断位置是否相等。
在java中判断字符串相等使用equal。
equals 给字符串比较的时候是值,给其他引用类型比较时,仍然是地址。
字符串常量池
字符串创建时,先从常量池中寻找,要是有的话就不再创建了,而是指向它。
但如果 是 new 出来的,则它是与众不同的,不进入常量池中,而是单独创建。
空串和null串
空串和null串并不相同:
空串""是有空间的,而null是空引用不占空间。
码点与代码单元
public class Test{
public static void main(String[] xxx){
String x1 = "abcdefghijklmn";
int w1 = x1.length(); // 获取字符串的长度
char w2 = x1.charAt(3); // 获取第四个字符
int w3 = x1.codePointAt(3); // 获取第四个字符编码
int w4 = w2; // 这种获取编码的方式比较好记
System.out.println(w1);
System.out.println(w2);
System.out.println(w3);
System.out.println(w4);
}
}
String API
api:相当于一个帮助文档,可以查询现成的方法如何使用。
一些常用的:
通过看api就能知道对应如何使用:
public class Test{
public static void main(String[] xxx){
String s1= "abcdefg";
String s2 = "def";
String s3 = s1.replace("cd","kk"); //替换
int idx = s1.indexOf(s2); //子串起始位置
System.out.println(idx);
System.out.println(s3);
}
}
字符串数组
string.split(t) 根据t切割,返回字符串数组。
构建字符串
有些时候,需要由较短的字符串构建字符串,例如,按键或来自文件中的单词。采用字符串连接的方式达到此目的效率比较低。每次连接字符串,都会构建一个新的 String 对象 ,既耗时 , 又浪费空间。
使用 StringBuilder 类就可以避免这个问题的发生。
在需要构建字符串时就凋用 toString 方法,将可以得到一个 String 对象,其中包含了构建器中的字符序列。
StringBuilder();
toString();
public class Test{
public static void main(String[] xxx){
String a = "adsf";
a = a + "adfsdg";
StringBuilder b = new StringBuilder();
b.append("dfdf");
b.append("sdvfsv");
System.out.println(a);
System.out.println(b.toString());
}
}
简单对比一下时间:
public class Test{
public static void main(String[] xxx){
long start = System.currentTimeMillis();
String a ="";
for (int i = 0; i < 10000; i++){
a +="a";
}
long end = System.currentTimeMillis();
long start1 = System.currentTimeMillis();
StringBuilder b = new StringBuilder();
for (int i = 0; i < 10000; i++){
b.append("a");
}
long end1 = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(end1 - start1);
}
}
明显快很多很多。
时间戳currentTimeMillis()
所有计算机都是从1970年01月01日08时00分00秒开始计算的。
buffer机制
分页:是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。即划分逻辑地址空间至固定大小的页(Page),划分物理内存空间至固定大小的帧(Frame),并建立方案,转换逻辑地址为物理地址(pages to frames)。在 Linux 下,每一页的大小通常为 4KB。
StringBuilder 比 String 快的原因:
多个单个变量存储在多个页中,数组中的多个元素可以存在一个页中,一个页是4KB。 // 这里写的不一定对。有知道的可以纠正一下。
所以实际上的内存占用要比想象中多的多。
String字符串不可变,每次改变都要占用4kb大小去储存新的,这样内存会浪费很多,内存压力大,运行速度自然也会很慢。
而StringBuilder内存可以指定。会提前申请8kb的足够空间,每次修改就可以有充足的空间在原地址修改,自然就快了。
底层就是开辟一个较大的数组。
StringBuffer 底层就是char 数组。
像这种提前申请空间节省内存的机制叫做 buffer 机制。
常用来处理文件流,网络流。
流:本质就是基本类型数组。
String、StringBuilder、StringBuffer 区别
StringBuffer 里面加了锁,保障多线程下的安全,速度稍微慢一丢丢。也差不多,都是远远快于String。
比特流、网络流、文件流
上面也说了流本质就是基本类型数组。
如:byte二进制每8位存进数组一个数、
short二进制每16位存入数组一个数。其他与之类似。
一般都用byte数组是一个万能数组,因为其他类型都是他的倍数。
例如8位还原成32位:
文件流:文件以二进制存储,通过上述方式解析成数组后,通过编码再次解析,显示在我们的屏幕上。 不同文件的头部会有不同固定的bit来记录是哪种编码。
网络流:与文件流相同的原理。