java road

String-学习笔记(1)

2018-08-19  本文已影响31人  HardWJJ

String对象的不变性

对String对象的任何改变都不会影响到原对象,相关的任何change操作都会生成新的对象

例:

String str = "abc";

相当于

char data[] = {'a', 'b', 'c'};
String str = new String(data);

1、定义

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {}

表示此类无法被继承

序列化的标记,该接口没有任何实现

字符序列,CharBuffer、String、StringBuffer、StringBuilder四个类都实现了这个接口

2、属性

/** The value is used for character storage. */
private final char value[];

String类用于存储数据的地方,可以看出String存储数据是基于char数组来实现的,由于声明为final,所以一旦初始化后就不能进行更改

/** Cache the hash code for the string */
private int hash; // Default to 0

字符串的hash值,默认为0

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;

由于实现了Serializable接口,所以可以为类添加serialVersionUID,添加后可以保证在进行序列化后进行反序列化时版本的一致性,如果不指定ID,如果修改类的状态JVM会根据类的状态为类生成一个新ID,这样反序列化后ID不一致而导致反序列化失败

/** Class String is special cased within the Serialization Stream Protocol.*/
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];

3、构造方法

String类中重载的构造方法比较多,这里列举几种常用的构造方法

1、public String()
初始化一个新的字符串,value属性的值为""(空串)的字符数组
2、public String(String original)
基于传入的字符串构造一个String

1、public String(char value[])
方法调用链:Arrays.copyOf - > System.arraycopy
其中System.arraycopy是一个native方法,方法的作用是将传入的字符数组逐个的复制到String的value属性的字符数组中
2、public String(char value[], int offset, int count)
offset是起始位置,count,是复制的长度,调用链与1相同,但可以根据传入的字符数组指定复制的起始位置

1、public String(int[] codePoints, int offset, int count)
根据传入的整型数组构成String字符串

1、public String(byte bytes[])
2、public String(byte bytes[], int offset, int length)
3、public String(byte bytes[], Charset charset)
4、public String(byte bytes[], String charsetName)
5、public String(byte bytes[], int offset, int length, Charset charset)
6、public String(byte bytes[], int offset, int length, String charsetName)


将传入的byte[]数组转为String字符串的时候需要考虑编码与解码的问题,构造函数中的charsetName与charset可以指定将传进来的byte数组转为对应String的字符数组


在进行解码的的时候共有两种解码方法,分别是StringCoding类的两个重载方法:
1、static char[] decode(String charsetName, byte[] ba, int off, int len)
在调用如果没有指定字符编码,默认采用ISO-8859-1编码

String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;

2、static char[] decode(Charset cs, byte[] ba, int off, int len)
在调用前必须指定相应解码器,否则抛出运行时异常

public String(byte bytes[], int offset, int length, Charset charset) {
      if (charset == null)
        throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);
}

1、public String(StringBuilder builder)
2、public String(StringBuffer buffer)
对于StringBuilder和StringBuffer这两个类,可以直接使用重写的toString方法获取字符串,在效率上,StringBuilder比StringBuffer快一点,因为StringBuffer加了synchronized,使用了同步机制

StringBuffer:
@Override
public synchronized String toString() {
   if (toStringCache == null) {
    toStringCache = Arrays.copyOfRange(value, 0, count);
   }
    return new String(toStringCache, true);
}
StringBuilder:
@Override
public String toString() {
    // Create a copy, don't share the array
     return new String(value, 0, count);
}

1、String(char[] value, boolean share)

/*
 * a separate constructor is needed because we already have a public
    * String(char[]) constructor that makes a copy of the given char[].
    */
    String(char[] value, boolean share) {
        // assert share : "unshared not supported";
        this.value = value;
    }

由注释可以看出,已经存在了public String(char[] value),加上boolean share只是为了进行重载之前存在的构造函数


这个构造方法的好处是无需像之前构造方法一样进行逐一复制,直接将属性value值指向新的引用数组。但这样就会破坏数组的不可变性,所以这个构造函数没有设置为Public

4、其他方法

返回字符串长度

判断字符串是否为空

返回字符串(index + 1)个字符

获取字符数组元素的代码点

返回 char 数组的给定索引前面的代码点

返回的是代码点个数,是实际上的字符个数

返回指定索引处的字符

将字符从字符串复制到目标字符数组

将字符从字符串复制到目标字符数组

返回对应的hash值,如果两个字符串value值相同,那么它们的hash值一定相同,如果它们的hash值相同,它们的value值不一定相同

在字符ch在字串fromindex位后出现的第一个位置

就是字符ch在字串fromindex位后出现的第一个位置

返回指定字符串从fromIndex最后一次出现str的位置

返回从beginIndex位置开始到最后的子字符串,对于substring方法,在java8中,将调用构造方法重写构建一个String,在Java7之前,substring方法返回的字符串中的value值指向被切割的字符数组,导致原来的字符串中的字符数组中只有一部分是有用的(substring方法返回的字符串),其余字符都是没用的,但是由于substring返回的字符串的引用,导致原来的字符串的整个字符数组都无法被释放

返回从起始索引到结束索引的子符串,包含起始索引,但不包含结束索引

返回相应字符串的子字符串,内部调用substring方法

在指定字符串的末尾加上Str

将字符串中指定的oldChar替换成newChar

判断字符串是否与给定的正则表达式匹配

判断字符串是否包含对应的s子序列,内部使用indexOf

,用replacement替换所有的regex(正则表达式)匹配项

和replaceAll相同,区别是只替换第一个匹配项

用replacement替换所有的target

通过delimiter连接符,连接多个elements

将字符串转为小写

将字符串转为大写

去除字符串首尾空格

返回当前字符串对象

将字符串对象中的字符转换为字符数组

返回指定的格式化的字符串

将指定的obj对象转换为String,该方法也有基本类型作为参数的重载

与valueOf方法类似,直接调用String构造方法创建新的String进行返回

调用该方法后,如果字符串常量池中已经有一个相等的字符串常量则返回其引用,如果没有则将字符串常量添加到对象池中然后再返回该字符串常量的引用

可将一个字符串转为字节数组,String提供了很多getBytes重载方法。由于是字符串与字节数组的互相转换,所以涉及到编码问题,当使用不带参数的getBytes方法时,会使用系统默认编码,中文系统下会使用GBK或者GB2312进行编码,英文系统下会使用iso-8859-1进行编码。为了不依赖运行的机器环境,可以通过上面两个getBytes方法来指定编码方式。

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;
    }

比较两个字符串是否相同,相同返回true,不同返回false,equals方法在进行真正的字符数组比较前先做了一系列的判断,采用不符合条件就尽快return的方式,相比直接比较两个字符串的字符数组减少了很多开销

比较两个字符串是否相同,相同返回true,不同返回false

 public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }

比较两个字符串是否相同,相同返回true,不同返回false,与上一个区别只是传入参数不同,在调用比较方法之前先判断是否属于AbstractStringBuilder,再判断是否是线程安全的类,最后再调用各自的方法,也就是先比较大的范围,再范围减小进行比较

比较两个字符串是否相同,与前面几个方法的区别在于比较前先全部转为大写

int compareToIgnoreCase(String str);
boolean regionMatches(int toffset, String other, int ooffset,int len) //局部匹配
boolean regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len) //局部匹配

5、对"+"字符的重载

"+"是java中唯一的重载运算符,底层使用的是StringBuilder类的append方法和toString方法

  public static void main(String[] args) {
        String string1="Hard";
        String string2 = string1 + "wjj";
    }

    反编译后:
  public static void main(String[] args) {
        String string1 = "Hard";
        String string2 = new     
       StringBuilder().append(string1).append("wjj").toString();
  }

6、将int转为字符串

1.int i = 5;
2.String i1 = "" + i;
3.String i2 = String.valueOf(i);
4.String i3 = Integer.toString(i);

第2个式子涉及到"+"的重载,调用过程和标题5一样,3和4的调用方式是一样的

public static String valueOf(int i) {
    return Integer.toString(i);
}

7、参考资料

上一篇下一篇

猜你喜欢

热点阅读