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可以创建对象,其内部是一个字符数组;
字符串常量池
·为什么要用字符串常量池?
因为我们经常要使用字符串,所以我们要用的时候直接调用即可。
好处:内存开销小,可以重用。
缺点:不便于修改,要想修改的话将创建新的对象。
如果是动态变量的情况将不会进行复用,以下代码可以体现
package mystring;
/**
* @author: 天天快乐的小亮
* @date: 2020/10/18 22:31
* @description:
*/
public class StringDemo1 {
public static void main(String[] args) {
String s1 = "ABC";
String s2 = "ABC";
//创建了新的 对象
String s3 = new String("ABC");
//不会对动态变量的值进行复用
String s4 = "ABCDE";
String s5 = s1+"DE";
System.out.println(s1 == s2);
System.out.println(s2 == s3);
System.out.println(s4 == s5);
}
}
经典面试题
String s3 = new String("ABC");
如上代码创建了几个字符对象?
如上代码创建了2个字符对象,1个字符串数组对象。
附加:
关于==和equals的区别和联系:
1、==比较基本数据类型比较的是值相等,比较的是引用数据类型比较的是地址值是否相等。
2、equals不能用于基本数据类型的比较,会报错。
1、equals()继承自object类
2、如果equals()没有重写,那么比较的还是地址,只有重写了才能
比较内容。
3、String、Date类多默认对equals()进行了重写。
/**
*String 类对equals()重写
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
注意点:
只有采用字面量的形式对String类型的变量赋值时,才会重用常量池中的值,如果new了一个对象出来,那么这两个对象肯定不是统一个对象了。(所以通常我们比较字符串的时候要用equals()而不能用==)
String s1="123abc";
String s4=new String("123abc");
System.out.println(s1==s4);//false
附加:
给出上面程序的输出?
解答:
上面的输出分别是
true
false
原因:s1的这种表达式因为在编译的时候就可以确定结果,所以不需要编译器出编译,所以可以将它当成字面量处理,而s3则是拼接了新的对象,对对象不一样,比较的结果肯定是不一样的。
这题考查的是编译器的一个特性,而并非字符串的知识点。
字符串的方法
length()获取字符串长度
package string;
/**返回字符串的长度
* @author 天天快乐的小亮
* @date 2019/10/20-16:44
*/
public class StringLengthDemo {
public static void main(String[] args) {
String str="学习java think in";
System.out.println(str.length());
}
}
IndexOf()
查找字符串的位置,位置到则返回-1
还有几个重载的方法
package string;
/**
* @author 天天快乐的小亮
* @date 2019/10/20-16:48
*/
public class StringIndexOfDemo {
public static void main(String[] args) {
String str="学习java think in";
System.out.println(str.indexOf("java"));//返回其位置为2
System.out.println(str.indexOf("javas"));//未找到则返回-1
}
}
subSting()(包头不包尾)
结合indexOf查找指定域名的名称。
package string;
/**
* 截取字符串 包头不包尾
*
* @author 天天快乐的小亮
* @date 2019/10/20-17:01
*/
public class StringSubString {
public static void main(String[] args) {
String str = "www.baidu.com";
System.out.println(str.substring(4, 9));//baidu
//还有个重载的方法 切一刀到末尾
System.out.println(str.substring(4));
//根据subString()截取域名
String url1="www.souhu.com";
String url2="https://.meituan.com";
String url3="www.hopu.com.cn";
//String hostName = getHostName(url1);
String hostName = getHostName(url2);
String hostName3 = getHostName(url3);
System.out.println(hostName3);
System.out.println(hostName);
}
/**
* 根据URL截取域名
*
* @param url
* @return 域名
*/
public static String getHostName(String url) {
//查第一个点出现的位置
int first = url.indexOf(".")+1;
//查第二个点出现的位置
int end=url.indexOf(".",first);
return url.substring(first,end);
}
}
trim()去字符左右两边空格
package string;
/**去字符左右两边空格
* @author 天天快乐的小亮
* @date 2019/10/20-19:38
*/
public class StringTrim {
public static void main(String[] args) {
String str=" helllo ";
//去除左右两边空格
System.out.println(str.trim());
}
}
charAt()根据索引查找指定字符串
package string;
/**
*charAt()根据索引查找指定字符串
* @author 天天快乐的小亮
* @date 2019/10/20-19:42
*/
public class ChaAtDemo {
public static void main(String[] args) {
String str="I love think in java!";
//根据索引查找指定字符串
System.out.println(str.charAt(5));
//查找每个字符
for (int i = 0; i <str.length() ; i++) {
System.out.println(str.charAt(i));
}
}
}
startsWith()和endsWith()
匹配是不是以某个字符开始或结束
package string;
/**
* 匹配是不是以某个字符开始或结束
*
* @author 天天快乐的小亮
* @date 2019/10/20-19:50
*/
public class StringStartsWith {
public static void main(String[] args) {
String str = "I love think in java!";
System.out.println(str.startsWith("java"));
}
}
valueOf()静态方法
package string;
/**
* 将类型转换成字符串类型
* @author 天天快乐的小亮
* @date 2019/10/20-19:54
*/
public class StringValueOf {
public static void main(String[] args) {
int i=10;
String s = String.valueOf(i);
System.out.println(s);
double j=20;
System.out.println(String.valueOf(j));
//或者直接加""
float c=30.0f;
String c1=c+"";
System.out.println(c1);
}
}
字符串频繁拼接带来的性能问题
下面的代码会频繁的创建对象,性能非常低(方式一)
package string;
/**
* 字符串频繁修改带来的性能问题
* @author 天天快乐的小亮
* @date 2019/10/20-20:39
*/
public class StringDemo2 {
public static void main(String[] args) {
String str="a";
for (int i = 0; i < 1000000; i++) {
str+="a";
System.out.println(str);
}
}
}
StringBuilder修改字符串操作
package string;
/**
* @author 天天快乐的小亮
* @date 2019/10/21-10:34
*/
public class StringBuilderDemo {
public static void main(String[] args) {
String str="I love java!";
StringBuilder stringBuilder=new StringBuilder(str);
/**
* append()拼接字符串
*
*/
StringBuilder str1 = stringBuilder.append(",为了迎娶白富美!");
System.out.println(str1);
/**
* insert() 插入字符串
*/
StringBuilder str2 = stringBuilder.insert(str.indexOf("!"), "、C#");
System.out.println(str2);
/**
* replace()替换
*/
StringBuilder str3 = stringBuilder.replace(7, 11, "JavaScript");
System.out.println(str3);
}
}
方式二
package string;
/**
* StringBuilder 的性能问题
* @author 天天快乐的小亮
* @date 2019/10/21-11:06
*/
public class StringBuilderDemo2 {
public static void main(String[] args) {
String str="a";
StringBuilder sb=new StringBuilder(str);
for (int i = 0; i < 1000000; i++) {
/*
采用stringBuilder执行字符串的修改操作效率是可观的
*/
sb.append("a");
}
System.out.println("执行完毕");
}
}
频繁修改字字符串的总结
因为方式二不会频繁的去创建stringBuilder对象,只是在后面进行拼接,所以相对方式一的效率会高很多。