public final class String implements java.io.Serializable,Comparable<String>,CharSequence{
}
String 类不属于基本数据类型,由于是final类型,所以不能被继承,但是可以序列化
/** The value is used for character storage. */
private final char value[];
使用final类型存储字符串内容,初始化后就不能被修改。
/**Cache the hash code for the String */
private int hash; //Default to 0;
指定缓存字符串的hash code的值,默认为0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
String实现了java.io.Serializble接口,支持序列化接口。
ps:序列化是为了存储整个对象,对象序列化的最主要用处就是在传递和保存对象(Objcet)的时候,保证对象的完整性很可传递性。譬如网络传输、或者把一个对象保存成一个文件的时候,要实现序列化接口。
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
ObjectStreamField数组用来申明一个类的序列化字段
String 类中final关键字的使用
final关键字,用来描述一块数据不能被改变,
final使用的三种情况,数据、方法、类,final修饰类、类不能被继承,final修饰方法,方法不能被重载。final修饰基本类型,使得数值不能被改变,但是用于对象引用,虽然能保证初始化后指定一个对象后,就无法指定其他对象,但是对象本身的值确实可以修改;(数组使用final修饰,引用地址不可改变,但是数组的数据却可以改变。);
这个时候 将Class String 使用final修饰,value[] 使用private授予私有访问权限,禁止String 类被继承,房子被子类改写,从而保证String的不可改变,保证其安全性。
了解内存分配和数据存储
数据存储:
1.寄存器:最快的存储区,位于处理器的内部,由于寄存器的数量有限,所以寄存器是按需分配的;ps:如何操作寄存器?寄存器的使用范例?什么时候使用寄存器?
2.栈:位于RAM(随机存储器),但是可以通过栈指针可以从处理器那里获得直接支持,栈指针向下移动,则分配新的内存,栈指针向上移动释放内存。ps:栈中存储基本数据类型和对象引用。但是java 的对象存放在堆中。
3.堆:通用内存池,位于RAM中,用于存放所有的java对象。ps:堆中存储的new创建的对象和数组。
4.常量存储:存放常量。ps:什么是常量。常量:固定不改变的量。一般用final修饰常量。
5.非RAM存储:数据不依赖于程序而存在,如:流对象和持久化对象。
java中基本类型的包装类大部分实现了常量池技术,这些类是Byte、Integer、Long、Character、Boolean,另外两种浮点数类型的包装类则没有实现,另外这5种类型的包装类也只是在对应的小于等于127和大于等于-128时才可使用对象池,不负责创建和管理大于127的这些类对象
String 实现了常量池技术
String 类是java中用的很多的类,同样为了创建String 对象的方便,也实现了常量池的技术。
public class Test{
public static void main(String[] args){
//s1,s2分别位于堆中不同空间
String s1=new String("hello");
String s2=new String("hello");
System.out.println(s1==s2)//输出false
//s3,s4位于池中同一空间
String s3="hello";
String s4="hello";
System.out.println(s3==s4);//输出true
}
}
StringBuffer 和 StringBuilder:java操作可变字符串的类。
StringBuffer源码分析:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
}
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
无参构造方法,构造一个初始容量为16的字符串缓冲区,同时提供多个有参的构造函数,如:
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* {@code 16} plus the length of the string argument.
* @param str the initial contents of the buffer.
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
// AbstractStringBuilder
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
append方法前加了同步锁,保证了线程安全,StringBuffer中很多方法都采用同步锁,保证了多线程操作时的同步安全。其中的ensureCapacityInternal方法中对存储空间的分配,如果存储空间不够用的时候,重新new char[] ,存储空间大小为(原始大小+1)*2,最大值为Integer.MAX_VALUE;
StringBuilder跟StringBuffer的操作逻辑一致,只是没有做同步处理。
总结:
String:字符常量
StringBuffer:字符常量(线程安全)
StringBuilder:字符常量(非线程安全)
由此可知:在大部分的情况下,三者在执行速度方面:StringBuilder>StringBuffer>String
用法总结:
String:用于少量需要对字符串进行操作,因为String每次生成对象都会对系统性能产生影响,当内存中无引用对象产生过多时,GC就会开始开始工作。
StringBuilder:单线程下,多次大量的操作字符串,字符串处理时不会产生新的对象,而是对象自身做改变。
StringBuffer:多线程下,多次大量的操作字符串,字符串处理时不会产生新的对象,而是对象自身做改变。