字符串(1)- String

1.String
1)String类位于java.lang包中,代表字符串;Java把String类声明为final类,不能有子类;String类对象一旦创建后就不能够修改,其底层其实是由字符数组构成的。
2)常用方法
<1>新建字符串
String str = new String([字符串常量]);
String str = 字符串常量;
<2>构造方法

/*无参构造方法,创建空的字符串对象*/
   public String() {
        this.value = "".value;
    }
 /*通过字符串常量创建字符串对象*/
   public String(String original) {
       this.value = original.value;
       /*同时将字符串常量的hash code赋值给字符串对象*/
       this.hash = original.hash;
   }
/*通过字符数组创建字符串对象*/
public String(char value[]) {
      /*由于其底层是数组,只需将字符数组Copy一份至新字符串对象的value值即可*/
        this.value = Arrays.copyOf(value, value.length);
    }
/*通过字符串数组创建字符串对象,是从字符数组的第offset开始,count个字符创建的*/
public String(char value[], int offset, int count) {
    //对参数offset进行合法性判断,不能<0,否则抛异常
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
      //对参数count进行合法性判断
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
        //count==0,offset<=value.length 则是空字符串
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
       //如果sffset+count的长度>value.length,也需要抛出异常
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
      //使用Arrays的copyOfRange();
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }
/*将字节数组按照字节码对应的字符转为字符串*/
public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }
public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }

<3>常用方法:
查找:

/*获取字符串长度*/
    public int length() {
      //返回字符数组长度
        return value.length;
    }
/*查找指定位置字符,第一个字符下标是0*/
 public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }
/*提取子字符串,提取的是从beginIndex到结尾的子字符串*/
public String substring(int beginIndex) {
      //对beginIndex进行合法性判断
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //new 一个String对象,通过String(char value[], int offset, int count)构造方法
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

/*提取子串,获取从beginIndex到endIndex*/
public String substring(int beginIndex, int endIndex) {
      //对参数进行合法性判断
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

获取字符位置:

/*获取字符ch在字符串中的位置(数组下标)*/
public int indexOf(int ch) {
        return indexOf(ch, 0);
    }
/*从fromIndex位置开始查找,获取字符ch在字符串中的位置(数组下标)*/
public int indexOf(int ch, int fromIndex) {
        final int max = value.length;
        if (fromIndex < 0) {
            fromIndex = 0;
        } else if (fromIndex >= max) {
            // Note: fromIndex might be near -1>>>1.
            return -1;
        }
      //public static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x010000;
  //判断是否在65536范围内,在范围内直接查找就可以,不在则说明是补充字符码,使用indexOfSupplementary(ch, fromIndex)方法;
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            for (int i = fromIndex; i < max; i++) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }

获取子字符串位置

/*获取子字符串在字符串中出现的首次位置*/
public int indexOf(String str) {
        return indexOf(str, 0);
    }
/*从fromIndex开始查找,获取子字符串在字符串中出现的首次位置*/
public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
/*与上边两个方法类似,不过从字符串的末尾往前查询*/
 public int lastIndexOf(String str) {
        return lastIndexOf(str, value.length);
    }
 public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }


/*source字符串, sourceOffset开始位置, sourceCount字符串长度,target子字符串, targetOffset开始位置, targetCount子字符串长度, fromIndex字符串开始查询的位置*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        //参数合法性判断,0<fromIndex<=sourceCount
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }
        //先查找子字符里的第一个字符在字符串中的位置
        char first = target[targetOffset];
        //最多查到字符串的倒数targetCount个位置,超出这个位置剩下的就一定不存在子字符串了

        int max = sourceOffset + (sourceCount - targetCount);
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
              //又加了一层判断?
                while (++i <= max && source[i] != first);
            }
             //如果第一个存在,则查找该子字符串中在字符串中的接下来的位置是否存在
            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }

比较:

/*比较两个字符串是否相等,比较的是内容*/
public boolean equals(Object anObject) {
      //如果是同一对象,一定相等
        if (this == anObject) {
            return true;
        }
        //anObject是否是String的一个实例
        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;
    }
/*忽略大小写比较两个字符串是否相等*/
public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }

/*两个字符串大小比较,返回值是两个字符串的长度之差或者第一个不相等字符的字符码之差*/
 public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
       //得到两个字符串长度小的
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                //,如果是在两个字符串中短者的范围内,返回的事第一个不相等字符的Unicode码之差
                return c1 - c2;
            }
            k++;
        }
      //返回的是字符串长度之差,其实也就是说其中一个是另一个的子串时候,返回的是长度之差。
        return len1 - len2;
    }

/*忽略大小写的比较大小*/
public int compareToIgnoreCase(String str) {
        //CASE_INSENSITIVE_ORDER.compare(this, str);是String类的一个静态内部类
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;
        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
          //将字符串循环,然后通过Character的大小写转换,进行比较
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }

拼接:

/*将字符串拼接到已知字符串之后,与+类似*/
public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
       //数组扩容
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        //返回的是一个新的字符串对象!
        return new String(buf, true);
    }

替换:

/*字符替换,返回的是替换后的新字符串*/
public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }
/*替换第一次匹配到的字符串*/
public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }
/*字符串替换*/
public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

转换:

public String toLowerCase(){...}//返回将当前字符串中所有字符转换成小写后的新串
public String toUpperCase(){...}//返回将当前字符串中所有字符转换成大写后的新串
public static String valueOf(Object obj){...}//基本数据类型转字符串,参数可以是任意字符串类型

其他:

public String[] split(String str){...}//将str作为分隔符进行字符串分解,分解后的字字符串在字符串数组中返回。
public String trim(){...}//截取字符串两头的空格,对于中间的空格不做处理。
public boolean contains(String str)//判断参数s是否被包含在字符串中,并返回一个布尔类型的值

3)字符串常量池
<1>字符串是存储在字符串常量池中的,字符串常量池是位于方法区中的;
<2>字符串在创建时候是先在字符串常量池中查看是否已经有该字符串,如果有就直接引用到该字符串,没有的话就先创建该字符串,然后引用:
String str1 = "ABC";
在字符串常量池中创建"ABC",str直接指向该字符串
String str2 = new String("ABCD");
在字符串常量池中创建"ABCD"对象,然后在堆中新建new String("ABCD")对象,然后str指向该对象
String str3 = new String("A"+"B");
在字符串常量池中新建了"A","B","AB"三个对象,然后再堆中新建了一个new String("AB")对象,然后str3指向该对象
String str4 = new String("ABCDE")+"ABCDE";//
在字符串常量池中创建"ABCDE"对象,然后新建new String("ABCDE")对象,然后在字符串常量池中创建"ABCDEABCDE"对象,然后str4指向该常量池中的字符串
<3>使用字符串常量池的好处:字符串是作为最基础的引用数据类型,使用率是极高的,大量频繁的创建销毁对象,对于性能有很大的影响,因此使用字符串常量池,使得字符串常量池中的字符串不会被垃圾回收机制回收,在不会影响其他对象对字符串的引用;并且将字符串放进字符串常量池后,是不会再改变该字符串的,可以不用担心数据共享时候的冲突。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 从网上复制的,看别人的比较全面,自己搬过来,方便以后查找。原链接:https://www.cnblogs.com/...
    lxtyp阅读 1,344评论 0 9
  • 前言 RTFSC (Read the fucking source code )才是生活中最重要的。我们天天就是要...
    二毛_coder阅读 445评论 1 1
  • String 的声明 由 JDK 中关于String的声明可以知道: 不同字符串可能共享同一个底层char数组,例...
    CodeKing2017阅读 1,616评论 1 2
  • 概述 在分析字符串常量池之前,先来分析一下java的内存区域,然后再各种的情况分析一下各种情况下的情况; 在《深入...
    riverhh阅读 826评论 0 2
  • 前面我们总结了数组操作,这里我们将总结字符串相关的知识,除了总结String的API用法,同时我们还会总结一些相关...
    HCherisher阅读 3,600评论 2 6