不看你绝对后悔
1、看String类的定义
(1)基本的定义
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
private int hash; // Default to 0
private static final long serialVersionUID = -6849794470754667710L;
public String() {
this.value = "".value;
}
- 它实现了
java.io.Serializable
,Comparable<String>
,CharSequence
三大接口【马上讲解三大接口】 - 用
final char value[]
定义的一个char数组【原来如此,用final定义了,不能修改的原因】 - Comparable这个接口不讲,我主页讲过Comparable和Comparator的文章,可以去参考
(2)看它的构造方法
//不用看内部实现
public String() {
this.value = "".value;
}
//不用看内部实现
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
//不用看内部实现
public String(char value[], int offset, int count) {
}
//不用看内部实现
public String(int[] codePoints, int offset, int count) {
}
@Deprecated
public String(byte ascii[], int hibyte, int offset, int count)
}
@Deprecated
public String(byte ascii[], int hibyte) {
}
从上面我们可以收获如下东西
- @Deprecated:这个注解,是表示这个方法是过期的。
- @NotNull注解:可以看这篇文章,大致也就是就是不能为这个参数不能为null,你实例化的时候不能什么都不填
2、看StringBuffer和StringBuilder
(1)先看StringBuffer
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
private transient char[] toStringCache;
static final long serialVersionUID = 3388685877147921107L;
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
从里面可以获得如下东西
- 继承了
AbstractStringBuilder
抽象类,实现了:java.io.Serializable, CharSequence
接口 - 内部定义了:
toStringCache
的char数组进行数据的处理 - 然后其他的方法就是都用到了关键字:synchronized定义的方法实现了线程同步【这个就是和StringBuilder的区别所在,这样会降低速度】
- 其次是构造方法:你可以这样
public StringBuffer()
直接定义一个StringBuffer类来完成操作,它默认toStringCache
大小为16进行操作,下次是自动添加16,不会导致栈溢出的问题。你也可以通过public StringBuffer(int capacity)
指定实力话大小,进行操作。
(2)再来看StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
static final long serialVersionUID = 4383685877147921099L;
public StringBuilder() {
super(16);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
- 同样的继承了
AbstractStringBuilder
抽象类,实现了:java.io.Serializable, CharSequence
接口 - 其他的构造方法呀,都和上面个类一样
- 但是它居然连一个存储数据的数组都不给,但是它调用的super点进去就跳到了
AbstractStringBuilder
类里面去了,去康康这个类
(3)AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
- 它也实现了
Appendable, CharSequence
接口 - 原理保存数据的数组在这里面定义了
这里的小总结:我们通过AbstractStringBuilder定义了一些统一的操作,StringBuffer和StringBuilder都实现了这个抽象类来执行共同的操作,不同点在一个用了关键字synchronized定义了方法,实现线程同步,都是初始化了16的数组大小来完成操作
3、再来看他们三个的共同点
(1)public interface Appendable接口
- 这个接口已经走到了本次继承关系的尽头【没有再去实现其他接口什么的了】
- 来看它的源代码
package java.lang;
import java.io.IOException;
/**
* An object to which <tt>char</tt> sequences and values can be appended. The
* <tt>Appendable</tt> interface must be implemented by any class whose
* instances are intended to receive formatted output from a {@link
* java.util.Formatter}.
/**
* 可以将字符序列和值追加到其中的对象。
* Appendable接口必须实现,该类的实例旨在从java.util.Formatter接收格式化的输出。
*
* <p> The characters to be appended should be valid Unicode characters as
* described in <a href="Character.html#unicode">Unicode Character
* Representation</a>. Note that supplementary characters may be composed of
* multiple 16-bit <tt>char</tt> values.
*
* <p> Appendables are not necessarily safe for multithreaded access. Thread
* safety is the responsibility of classes that extend and implement this
* interface.
*
* <p> Since this interface may be implemented by existing classes
* with different styles of error handling there is no guarantee that
* errors will be propagated to the invoker.
* <p> 对于多线程访问来说,Appendables不一定是安全的。
* 线程安全是扩展和实现这个接口的类的职责。
*
* <p> 由于这个接口可以由具有不同风格的错误处理的现有类实现,因此不能保证错误将传播到调用程序。
* @since 1.5
*/
public interface Appendable {
}
说人话就是总结如下
- 接口是非线程安全的
- 如果要去修改我们的char定义的对象,那你必须实例化这个接口
(2)public interface CharSequence接口
不难发现我们三个类:StringBuffer,StringBuilder,String都实现了CharSequence接口,那他到底是干嘛的呢?
下面这些方法都熟悉吧
原来如此:这个类接口定义了实现这个接口的类,必须实现的一些方法,计算其长度啊,所以你的String,StringBuffer等都可以计算长度,获得第一个字母等方法,所以理解了吧,CharSequence定义了标准,让你实现类去实现。
(3)public interface java.io.Serializable
这个的话,太简单了,就是为了方便在网上传输,然后就可以实现这个接口,它内部实现了。但是,但是,但是,请你记住,你要在网上传输的类都请实现这个接口
4、总结
(1)本次的收获
- 了解了他们几个的关系吧
- 知道了他们操作的流程吧
- 了解了继承关系吧
- 补充了自己不知道的几个接口吧
- 反正都是那玩意,你理解就可以了
(2)补充知识1
是这样的一个问题:我们每次实话一个StringBuffer或者StringBuilder对象都是实例化长度都是16,如果我们一直对字符串进程添加知道超过初始化定义的长度会不会报错呢?
- 答案是不会的
- 因为我们再进去康康添加的方法:点StringBuffer或者StringBUilder都可以,都会走到我们的AbstractStringBuilder类里面的添加方法
- 观察方法不难发现都在天机方法里面调用了
ensureCapacityInternal
方法,去康康ensureCapacityInternal
是何方神圣
- 它
ensureCapacityInternal
又去调佣了newCapacity,哦,懂了懂了,它在每次都会去判断是否会超过其长度,如果超过了翻一倍其长度+2 。所以不会有栈溢出的情况发生。
- 观察方法不难发现都在天机方法里面调用了
但是,但是,但是上面讲解的情况不是下面的这种情况哦【自己想一下为什么】
(3)补充知识2
- 问题:String str = new String(“xxx”)和String str = “xxx”;一样吗?
- 问题:String str1 = new String(“AAA”);String str2 = new String(“AAA”);str1和Str2一样吗
答案:是不一样
- 为什么呢?可以自己去找找看,我这就不详细讲解了,是关于java内存结构和常量池的一些关系
(3)补充知识3
- 问题:都说String定义了的常量是不能修改的,并且JDK也自己没有提供可修改的方法?比如:String str = “xxx”,
- 那到底能不能修改呢?答案是可以,各位可以去看这一篇文章,并且帮他和我点个赞
https://blog.csdn.net/C_Xiang_Falcon/article/details/102594585?
- 那到底能不能修改呢?答案是可以,各位可以去看这一篇文章,并且帮他和我点个赞