1.String java.lang包下 java字符串
-
String
类代表字符串。Java程序中的所有字符串文字(例如"abc"
)都被实现为此类的实例。字符串不变; 它们的值在创建后不能被更改。 字符串缓冲区支持可变字符串。 因为String对象是不可变的,它们可以被共享。 例如:
String str = "abc";
相当于:
char data[] = {'a', 'b', 'c'}; String str = new String(data);
以下是一些如何使用字符串的示例:
System.out.println("abc"); String cde = "cde"; System.out.println("abc" + cde); String c = "abc".substring(2,3); String d = cde.substring(1, 2);
String
类包括用于检查序列的各个字符的方法,用于比较字符串,搜索字符串,提取子字符串以及创建将所有字符翻译为大写或小写的字符串的副本。Java语言为字符串连接运算符(+)提供特殊支持,并为其他对象转换为字符串。 字符串连接是通过
StringBuilder
(或StringBuffer
)类及其append
方法实现的。 字符串转换是通过方法来实现toString
,由下式定义Object
和继承由在Java中的所有类。 有关字符串连接和转换的其他信息,请参阅Gosling,Joy和Steele, Java语言规范 。除非另有说明,否则传递
null
参数到此类中的构造函数或方法将导致抛出NullPointerException
。A
String
表示UTF-16格式的字符串,其中补充字符由代理对表示 索引值是指char
代码单元,所以补充字符在String中使用两个String
。String
类提供处理Unicode代码点(即字符)的方法,以及用于处理Unicode代码单元(即char
值)的方法。
说到String 就不得不提到一个关键字 final String是 被final修饰的
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
在java中被final修饰的类 不可以被继承,对于java来讲 提高了安全性;另外**String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,任何相关的change操作都会产生新的对象。**所以在日常开发中 尽量不要用 String拼接
2.字符串常量池
我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
常量池又分为静态常量池和运行时常量池 即.class文件中常量池
运行时常量池 则是jvm虚拟机在完成类装载后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池就是指方法区中的运行时常量池。
String a = "zy";
String b = "zy";
//所以 a==b 是true
String c = new String("zy");
String d = new String("zy");
//a==c 是false
//c==d 是false
当创建a的时候 ,jvm会首先判断字符串常量池中有没有“zy”,有,则直接把“zy”的引用地址返回给a,没有则创建,同理b也是;所以a==b是true,
a==c是false 原因在于 new String() 创建的是一个对象,而非常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,他们有自己的地址空间;
c==d是false c和d指向的是两个不同的对象;
String str1 = "abc";
String str2 = "def";
String str3 = str1+str2;
System.out.println(str3=="abcdef"); //false
这段代码一共创建了五个对象,常量池三个 “str1”,“str2” 和 “abcdef”;
堆中的"str3"和(“str1”+“str2”产生的一个新的String对象 “abcdef”)(“+”号会在堆中产生新对象)所以str3 指向的对象在堆中,而“abcdef”在池中,输出为false。
3.StringBuilder
-
一个可变的字符序列。此类提供与
StringBuffer
的API,但不保证同步。此类设计用作简易替换为StringBuffer
在正在使用由单个线程字符串缓冲区的地方(如通常是这种情况)。在可能的情况下,建议使用这个类别优先于StringBuffer
,因为它在大多数实现中将更快。StringBuilder的主要
StringBuilder
是append
和insert
方法,它们是重载的,以便接受任何类型的数据。 每个都有效地将给定的数据转换为字符串,然后将该字符串的字符附加或插入字符串构建器。append
方法始终在构建器的末尾添加这些字符;insert
方法将insert
添加到指定点。例如,如果
z
引用当前内容为“start
”的字符串构建器对象,那么方法调用z.append("le")
将导致字符串构建器包含“startle
”,而z.insert(4, "le")
会将字符串构建器更改为包含“starlet
”。一般情况下,如果某人是指的一个实例
StringBuilder
,则sb.append(x)
具有相同的效果sb.insert(sb.length(), x)
。每个字符串构建器都有一个容量。 只要字符串构建器中包含的字符序列的长度不超过容量,则不需要分配新的内部缓冲区。 如果内部缓冲区溢出,则会自动变大。
StringBuilder的
StringBuilder
不能安全使用多线程。 如果需要同步, 那么建议使用StringBuffer除非另有说明,否则将
null
参数传递给null
中的构造函数或方法将导致抛出NullPointerException
。
4.StringBuffer
-
线程安全,可变的字符序列。字符串缓冲区就像一个
String
,但可以修改。在任何时间点,它包含一些特定的字符序列,但可以通过某些方法调用来更改序列的长度和内容。字符串缓冲区可以安全地被多个线程使用。 这些方法在必要时进行同步,以便任何特定实例上的所有操作都按照与所涉及的各个线程所执行的方法调用顺序一致的顺序发生。
StringBuffer的主要
StringBuffer
是append
和insert
方法,它们被重载以便接受任何类型的数据。 每个都有效地将给定的数据转换为字符串,然后将该字符串的字符附加或插入到字符串缓冲区。append
方法总是在缓冲区的末尾添加这些字符;insert
方法将insert
添加到指定点。例如,如果
z
是指当前内容为"start"
的字符串缓冲区对象,那么方法调用z.append("le")
将使字符串缓冲区包含"startle"
,而z.insert(4, "le")
会将字符串缓冲区更改为包含"starlet"
。一般情况下,如果某人是指的一个实例
StringBuffer
,则sb.append(x)
具有相同的效果sb.insert(sb.length(), x)
。每当涉及源序列(例如从源序列追加或插入)的操作发生时,该类仅在执行操作的字符串缓冲器上进行同步,而不在源上。 请注意,虽然
StringBuffer
被设计为可以安全地从多个线程并发使用,但如果构造函数或append
或insert
操作被传递通过线程共享的源序列,则调用代码必须确保该操作具有一致且不变的视图在操作期间的源序列。 呼叫者通过使用不可变的源序列,或者不跨线程共享源序列,可以在呼叫期间持有锁来满足这一点。每个字符串缓冲区都有一个容量。 只要字符串缓冲区中包含的字符序列的长度不超过容量,就不必分配新的内部缓冲区数组。 如果内部缓冲区溢出,则会自动变大。
除非另有说明,否则将
null
参数传递给null
中的构造函数或方法将导致抛出NullPointerException
。
- == 和 equals() 的区别
1.对于基本数据类型 ,int,short,long,byte,float,double,char,boolean.他们之间的比较用的 “==”,比较的是他们的值是否相同;
对于引用类型,当他们再用 “==”进行比较的时候,比较的是他们在内存中存放的地址,堆内存地址
2.equals() 方法,java中所有的类都是继承于Object这个超类的,object中有一个equels()方法;
public boolean equals(Object obj) {
return (this == obj);
}
这个方法的初始默认行为是比较对象的内存地址值对于引用类型来说 ,基本类型比较他们的值
所以说,对有引用类型之间进行equals比较,在没有重写equal() 方法的情况下 是和“==”一样的;
然后我们的String就重写了Object的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是final修饰的一个常量类,每一个字符串都是独一无二的,存储在方法区中的常量池中,java对于字符串拼接的支持导致每次 + 都会创建一个新的字符串,浪费内存,开销大,代码不严谨还会导致oom 所以对于字符串拼尽量使用StringBuilder ,多线程下使用StringBuffer,