本文已参与「新人创作礼」活动,一起开启掘金创作之路。
你真的会用String么?
String 是我们开发过程中经常会用到的变量类型,你天天在用,但是你真的会用string默认?
String
string也就是一个字符串是一个不可改变的字节序列。字符串可以包含任意的数据,但是通常是用来包含人类可读的文本。
首先来看一下Java中String的源码吧:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
...
/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param original
* A {@code String}
*/
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
...
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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的构造类里面:我用自己构造自己
- 比较equals时,有两个比较方式,一个时直接对象相等的方式,一个是比较对象中的value值
**不知道是什么意思?**看一下String初始化代码
String str1 = "hello world!";
String str2 = "hello world!";
String str3 = str1;
String str4 = new String("hello world!");
String str5 = new String("hello world!")
上面初始化的str1 - str5 都是相等的,有啥区别么? 内存分配使用不一样
str1 str2 str3 的变量是分配在公共区域的,而且指向的是同一片内存地址,也是是str1 str2 str3 其实只是别名,他们其实是同一个对象,也就是你用赋值方式使用string时,其实是指构造一次string,这么用更省内存。
使用new 构造函数来初始化string 就像 str4 str5 ,他们就是string的自己构造自己,他们是在堆上面分配内存用程序语言来说就是:
str4 == str5 是false
str4.equals(str5) 是true
构造巨大的string
由于string是一个字符串是一个不可改变的字节序列,所以你尝试去改变一个string时,其实你是创建了一个新的string。
public static void main(String[] args){
String str = "Hello " + "World" +"! " + "Welcome to using String";
String repeat = str + "\n";
String bigstr = "";
for (int i=0;i<1000000;i++){
bigstr += repeat;
}
System.out.println(bigstr.length());
}
上述代码如果在计算机上执行会创建多少对象呢? 创建str 用了4个对象 repeat 用了2个对象,bigstr用了1个对象for循环创建了10000000 个变量 如果你的计算机能运行上面的代码,恭喜你的计算机性能绝了,bigstring最终会占用70G左右的内存吧 使用StringBuilder 可以避免创建过多的中间变量 代码如下:
public static void main(String[] args){
String str = "Hello " + "World" +"! " + "Welcome to using String";
String repeat = str + "\n";
StringBuilder sb = new StringBuilder();
for (int i=0;i<1000000;i++){
sb.append(repeat);
}
System.out.println(sb.length());
}
这次sb占用的空间时30M左右
StringBuilder 和 StringBuffer
在用StringBuilder的时候是不是有人又和你说了StringBuffer,两者都是可以拼接字符串的,区别是:
- StringBuffer是线程安全的,StringBuilder是线程不安全的,当然StringBuffer的线程安全是牺牲了部分性能换来的。
- StringBuilder和StringBuffer的大部分方法均调用父类AbstractStringBuilder的实现。其扩容机制首先是把容量变为原来容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。
- 需要注意的是:StringBuilder和StringBuffer的默认容量都是16,最好预先估计好字符串的大小避免扩容带来的时间消耗。