String是一个不变的对象

简单的了解二进制

计算机的存储方式都是以二进制的形式完成的,用0、1来表示有电无电。
以8421原理可以进行简单的计算二进制。

字符集编码历史

最早的字符集编码ASCII,可以编码英文,和少数字符,用一个字节来表示。
ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符

GBK(可以编码中文了,占用两字节)

GBK即汉字内码扩展规范,K为扩展的汉语拼音中“扩”字的声母。英文全称Chinese Internal Code Specification。GBK编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,1980年由国家标准总局发布。基本集共收入汉字6763个和非汉字图形字符682个,通行于中国大陆。新加坡等地也使用此编码。GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展(之前CP936和GB 2312-80一模一样)。

Unicode编码(几乎覆盖了全球所有的语言)

如上ANSI编码条例中所述,世界上存在着多种编码
方式,在ANSi编码下,同一个编码值,在不同的编码体系里代表着不同的字。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,可能最终显示的是中文,也可能显示的是日文。在ANSI编码体系下,要想打开一个文本文件,不但要知道它的编码方式,还要安装有对应编码表,否则就可能无法读取或出现乱码。为什么电子邮件和网页都经常会出现乱码,就是因为信息的提供者可能是日文的ANSI编码体系和信息的读取者可能是中文的编码体系,他们对同一个二进制编码值进行显示,采用了不同的编码,导致乱码。这个问题促使了unicode码的诞生。

UTF-8

为了提高Unicode的编码效率,于是就出现了UTF-8编码。UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。

注:GBK的中文编码占用字节,UTF-8的中文编码占用3字节 。

String 是一个字称为字符串
1、String是一个类;
2、String 可以申明变量;
3、String可以创建对象,其内部是一个字符数组;

字符串常量池

·为什么要用字符串常量池?
因为我们经常要使用字符串,所以我们要用的时候直接调用即可。
image.png
好处:内存开销小,可以重用。
缺点:不便于修改,要想修改的话将创建新的对象。
如果是动态变量的情况将不会进行复用,以下代码可以体现

  1. package mystring;
  2. /**
  3. * @author: 天天快乐的小亮
  4. * @date: 2020/10/18 22:31
  5. * @description:
  6. */
  7. public class StringDemo1 {
  8. public static void main(String[] args) {
  9. String s1 = "ABC";
  10. String s2 = "ABC";
  11. //创建了新的 对象
  12. String s3 = new String("ABC");
  13. //不会对动态变量的值进行复用
  14. String s4 = "ABCDE";
  15. String s5 = s1+"DE";
  16. System.out.println(s1 == s2);
  17. System.out.println(s2 == s3);
  18. System.out.println(s4 == s5);
  19. }
  20. }

经典面试题

  1. String s3 = new String("ABC");

如上代码创建了几个字符对象?
如上代码创建了2个字符对象,1个字符串数组对象。
image.png

附加:

关于==和equals的区别和联系:
1、==比较基本数据类型比较的是值相等,比较的是引用数据类型比较的是地址值是否相等。
2、equals不能用于基本数据类型的比较,会报错。
image.png
1、equals()继承自object类
2、如果equals()没有重写,那么比较的还是地址,只有重写了才能
比较内容。
3、String、Date类多默认对equals()进行了重写。

  1. /**
  2. *String 类对equals()重写
  3. */
  4. public boolean equals(Object anObject) {
  5. if (this == anObject) {
  6. return true;
  7. }
  8. if (anObject instanceof String) {
  9. String anotherString = (String)anObject;
  10. int n = value.length;
  11. if (n == anotherString.value.length) {
  12. char v1[] = value;
  13. char v2[] = anotherString.value;
  14. int i = 0;
  15. while (n-- != 0) {
  16. if (v1[i] != v2[i])
  17. return false;
  18. i++;
  19. }
  20. return true;
  21. }
  22. }
  23. return false;
  24. }

注意点:

只有采用字面量的形式对String类型的变量赋值时,才会重用常量池中的值,如果new了一个对象出来,那么这两个对象肯定不是统一个对象了。(所以通常我们比较字符串的时候要用equals()而不能用==)

  1. String s1="123abc";
  2. String s4=new String("123abc");
  3. System.out.println(s1==s4);//false

附加:

image.png
给出上面程序的输出?
解答:
上面的输出分别是
true
false
原因:s1的这种表达式因为在编译的时候就可以确定结果,所以不需要编译器出编译,所以可以将它当成字面量处理,而s3则是拼接了新的对象,对对象不一样,比较的结果肯定是不一样的。
这题考查的是编译器的一个特性,而并非字符串的知识点。

字符串的方法

length()获取字符串长度

  1. package string;
  2. /**返回字符串的长度
  3. * @author 天天快乐的小亮
  4. * @date 2019/10/20-16:44
  5. */
  6. public class StringLengthDemo {
  7. public static void main(String[] args) {
  8. String str="学习java think in";
  9. System.out.println(str.length());
  10. }
  11. }

IndexOf()

查找字符串的位置,位置到则返回-1
还有几个重载的方法
image.png

  1. package string;
  2. /**
  3. * @author 天天快乐的小亮
  4. * @date 2019/10/20-16:48
  5. */
  6. public class StringIndexOfDemo {
  7. public static void main(String[] args) {
  8. String str="学习java think in";
  9. System.out.println(str.indexOf("java"));//返回其位置为2
  10. System.out.println(str.indexOf("javas"));//未找到则返回-1
  11. }
  12. }

subSting()(包头不包尾)

结合indexOf查找指定域名的名称。

  1. package string;
  2. /**
  3. * 截取字符串 包头不包尾
  4. *
  5. * @author 天天快乐的小亮
  6. * @date 2019/10/20-17:01
  7. */
  8. public class StringSubString {
  9. public static void main(String[] args) {
  10. String str = "www.baidu.com";
  11. System.out.println(str.substring(4, 9));//baidu
  12. //还有个重载的方法 切一刀到末尾
  13. System.out.println(str.substring(4));
  14. //根据subString()截取域名
  15. String url1="www.souhu.com";
  16. String url2="https://.meituan.com";
  17. String url3="www.hopu.com.cn";
  18. //String hostName = getHostName(url1);
  19. String hostName = getHostName(url2);
  20. String hostName3 = getHostName(url3);
  21. System.out.println(hostName3);
  22. System.out.println(hostName);
  23. }
  24. /**
  25. * 根据URL截取域名
  26. *
  27. * @param url
  28. * @return 域名
  29. */
  30. public static String getHostName(String url) {
  31. //查第一个点出现的位置
  32. int first = url.indexOf(".")+1;
  33. //查第二个点出现的位置
  34. int end=url.indexOf(".",first);
  35. return url.substring(first,end);
  36. }
  37. }

trim()去字符左右两边空格

  1. package string;
  2. /**去字符左右两边空格
  3. * @author 天天快乐的小亮
  4. * @date 2019/10/20-19:38
  5. */
  6. public class StringTrim {
  7. public static void main(String[] args) {
  8. String str=" helllo ";
  9. //去除左右两边空格
  10. System.out.println(str.trim());
  11. }
  12. }

charAt()根据索引查找指定字符串

  1. package string;
  2. /**
  3. *charAt()根据索引查找指定字符串
  4. * @author 天天快乐的小亮
  5. * @date 2019/10/20-19:42
  6. */
  7. public class ChaAtDemo {
  8. public static void main(String[] args) {
  9. String str="I love think in java!";
  10. //根据索引查找指定字符串
  11. System.out.println(str.charAt(5));
  12. //查找每个字符
  13. for (int i = 0; i <str.length() ; i++) {
  14. System.out.println(str.charAt(i));
  15. }
  16. }
  17. }

startsWith()和endsWith()

匹配是不是以某个字符开始或结束

  1. package string;
  2. /**
  3. * 匹配是不是以某个字符开始或结束
  4. *
  5. * @author 天天快乐的小亮
  6. * @date 2019/10/20-19:50
  7. */
  8. public class StringStartsWith {
  9. public static void main(String[] args) {
  10. String str = "I love think in java!";
  11. System.out.println(str.startsWith("java"));
  12. }
  13. }

valueOf()静态方法

  1. package string;
  2. /**
  3. * 将类型转换成字符串类型
  4. * @author 天天快乐的小亮
  5. * @date 2019/10/20-19:54
  6. */
  7. public class StringValueOf {
  8. public static void main(String[] args) {
  9. int i=10;
  10. String s = String.valueOf(i);
  11. System.out.println(s);
  12. double j=20;
  13. System.out.println(String.valueOf(j));
  14. //或者直接加""
  15. float c=30.0f;
  16. String c1=c+"";
  17. System.out.println(c1);
  18. }
  19. }

字符串频繁拼接带来的性能问题

image.png

下面的代码会频繁的创建对象,性能非常低(方式一)

  1. package string;
  2. /**
  3. * 字符串频繁修改带来的性能问题
  4. * @author 天天快乐的小亮
  5. * @date 2019/10/20-20:39
  6. */
  7. public class StringDemo2 {
  8. public static void main(String[] args) {
  9. String str="a";
  10. for (int i = 0; i < 1000000; i++) {
  11. str+="a";
  12. System.out.println(str);
  13. }
  14. }
  15. }

StringBuilder修改字符串操作

  1. package string;
  2. /**
  3. * @author 天天快乐的小亮
  4. * @date 2019/10/21-10:34
  5. */
  6. public class StringBuilderDemo {
  7. public static void main(String[] args) {
  8. String str="I love java!";
  9. StringBuilder stringBuilder=new StringBuilder(str);
  10. /**
  11. * append()拼接字符串
  12. *
  13. */
  14. StringBuilder str1 = stringBuilder.append(",为了迎娶白富美!");
  15. System.out.println(str1);
  16. /**
  17. * insert() 插入字符串
  18. */
  19. StringBuilder str2 = stringBuilder.insert(str.indexOf("!"), "、C#");
  20. System.out.println(str2);
  21. /**
  22. * replace()替换
  23. */
  24. StringBuilder str3 = stringBuilder.replace(7, 11, "JavaScript");
  25. System.out.println(str3);
  26. }
  27. }

方式二

  1. package string;
  2. /**
  3. * StringBuilder 的性能问题
  4. * @author 天天快乐的小亮
  5. * @date 2019/10/21-11:06
  6. */
  7. public class StringBuilderDemo2 {
  8. public static void main(String[] args) {
  9. String str="a";
  10. StringBuilder sb=new StringBuilder(str);
  11. for (int i = 0; i < 1000000; i++) {
  12. /*
  13. 采用stringBuilder执行字符串的修改操作效率是可观的
  14. */
  15. sb.append("a");
  16. }
  17. System.out.println("执行完毕");
  18. }
  19. }

频繁修改字字符串的总结

因为方式二不会频繁的去创建stringBuilder对象,只是在后面进行拼接,所以相对方式一的效率会高很多。