字符串
1. 创建字符串
最简单的:
String str = "hello";
用构造函数创建字符串:
String str2=new String("hello");
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:
注意:
String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了
值的改变一定是因为指向了新的位置。
为什么不可更改?
底层限定大小的数组,空间提前声明好的。往后延伸,违法,自动拦截。
!! 字符串不可修改是 不能在原地址修改
!! 两个非基本类型,判断是否相等,是看他们的指向是否相同
String类型是指针类型。
字符串如果有 现成的 已经存在的,会指向现成的。
所以这两个地址相同。
常量池
String s1="aaa";
s1="zzz";
垃圾自动回收机制:
在Java中,如果有块区域没有被指向了,就会被自动回收。(不只java,在其他高级语言里也有)
但是字符串在常量池中,如果空间足够,不指向它,不会被回收。
如果下一个字符串指向它,有现成的直接用。
public class Main{public static void main(String[] aaa){int[] arr1={12,33};arr1=new int[]{1,2,3,4};String s1="aaa";//s1="zzz";String s2="aaa";String s3=new String("aaa");String s4=new String("aaa");System.out.println(s1==s2); //trueSystem.out.println(s1==s3); //falseSystem.out.println(s3==s4); //f}
}
凡是见到new,一定是触发底层的malloc,自己创建一个新的空间,不用现成的。
2. 字符串长度
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。
public class StringDemo {public static void main(String args[]) {String str = "hello";int len = str.length();System.out.println( "字符串长度 : " + len );}
}
3. 连接字符串
string1.concat(string2);
"我的名字是 ".concat("Lojarro");
常用:
使用'+'操作符来连接字符串
"Hello," + " Lojarro" + "!"
4. 字符串比较
s1.equals(s2)
equals比较的是值。
字符串比较:equals是最稳妥的方法。
System.out.println(s1.equals(s2)); //trueSystem.out.println(s1.equals(s3)); //trueSystem.out.println(s3.equals(s4)); //true
equals()作用:
每个类都有这个方法(不仅是字符串类)都是集成object类,默认和==一样比较指向是否相同。
- 字符串中对这个方法进行了重写,仅比较值。
- 重写equals还需要重写 hashcode(), 因为 hashmap 的使用需要这两个方法配合。
面试题还会问如何打配合,hashmap存放数据原理。
5. 空串和NULL串
String s1=null;String s2="";//{'\0'}
API:java应用程序编程接口。
一提到接口就是API。
String s1="abcdefghijklm";char m1=s1.charAt(4);System.out.println(m1);int m2=s1.codePointAt(4);System.out.println(m2);
charAt(int index) 返回char
使用最最频繁的打算法的
6. StringBuffer 和 StringBuilder类
System.currentTimeMillis()计算毫秒数(从1970年开始)
字符串拼接方法:
StringBuilder str2=new StringBuilder();
比
String str="";
for(int i=0;i<100;i++){str +="a";
}
快。
面试题
String类型 和 StringBuilder 类型和 stringBuffer 类型区别
① Stringbuilder和StringBuffer速度远远高于String。
② Stringbuilder多线程并发操作不安全和StringBuffer多线程并发操作下安全。
③ StringBuffer里面加了锁,速度稍微慢一点点。
计算机内存分配以内存页为单位,内存一字节是一个物理单元,每一个物理地址是一字节。CPU要存1万字节要下达1万次地址指令,要走总线,指令不能同时下,得排队过,来回1万次,消耗时间。
所以操作系统为了读取快一点,把整个内存分成内存页,每个内存页一个地址,下达一次指令要4096个字节(4KB),只需要下达三次地址指令。
为什么设成4KB而不是10KB、8KB?
内存页对外只有一个总地址,只能找到一个变量,其他找不到,如果放多个变量,是无法找到变量。所以一个内存页只能放一个变量。
int a=9;
int b=7;
int c=6;
三个变量理论上消耗12字节,实际消耗12KB。
int[] arr={9,8,6}
数组是可以放在一个内存页里的,因为数据类型相同。
变量无法确定长度。
弱类型语言:默认不区分类型
python PHP js 这些弱类型语言底层还是C
{"s","sdsf",235,25.435F,{1,2,3}} 默认是一样的,内存存数据时放到一块,但是转化为C语言时还是需要分类,消耗很多内存页,所以慢。
对内存的消耗太大,所以他很慢。
一个内存页只能放一个变量,意味着多余的空间被浪费了。
- 内存页越大,读取的次数少,读取的速度快,浪费空间多
- 内存页越小,读取的次数多,读取的速度慢,浪费空间少
所以折中取了4KB。
申请1KB也是给4KB-->操作系统最小的分配单元就是4KB。
由于字符串的不可变,所以string的拼接的话,1000次修改就得申请1000*4KB=4000KB 内存空间。
由于本地址值的不可变,100000次需要消耗1.2GB的内存空间。
本地可变可以极大地降低内存的损耗。
Stringbuilder可以指定申请多大空间。本地可变
空间越大,缓冲的越多。
先申请足够大的空间,缓冲一段时间;不够了再申请,再缓存。
缓冲区--Buffer:足够大的数组。极大降低内存的损耗,提高速度。
跨语言,不分语言。
凡是以后见Buffer的,底层都是足够大的数组,对内存的损耗都很少,速度都很快。
文件流操作、网络流操作 容易用到缓冲区。
stream流 也是数组。
StringBuffer 是 Stringbuilder 的前身。
7. 输入输出
import java.util.*;//打算法比赛,先写这一句
public class Main{public static void main(String[] aaa){System.out.println( Arrays.toString(aaa) );}
}
main方法传的是字符串。
import java.util.*;//打算法比赛,先写这一句
public class Main{public static void main(String[] aaa){System.out.println( Arrays.toString(aaa) );Scanner x=new Scanner(System.in);int k1=x.nextInt();int k2=x.nextInt();float k3=x.nextFloat();System.out.println(k1+","+k2+","+k3);}
}
注意:
空格,回车 也属于字符串
import java.util.*;//打算法比赛,先写这一句
public class Main{public static void main(String[] aaa){System.out.println( Arrays.toString(aaa) );Scanner x=new Scanner(System.in);int k1=x.nextInt();int k2=x.nextInt();float k3=x.nextFloat();String k4=x.nextLine();k4=x.nextLine();String k5=x.nextLine();String k6=x.nextLine();String k7=x.nextLine();System.out.println(k1+","+k2+","+k3);System.out.println(k4);System.out.println(k5);System.out.println(k6);System.out.println(k7);}
}
会吃一次回车,所以多设一次。
如果前面没有别的输入,就不用多设了。