JDK中String类的源码分析(二)

1、startsWith(String prefix, int toffset)方法

包括startsWith(*),endsWith(*)方法,都是调用上述一个方法

 1     public boolean startsWith(String prefix, int toffset) {
 2         char ta[] = value;
 3         int to = toffset;
 4         char pa[] = prefix.value;
 5         int po = 0;
 6         int pc = prefix.value.length;
 7         // Note: toffset might be near -1>>>1.
 8         if ((toffset < 0) || (toffset > value.length - pc)) {
 9             return false;
10         }
11         while (--pc >= 0) {
12             if (ta[to++] != pa[po++]) {
13                 return false;
14             }
15         }
16         return true;
17     }

上述算法的时间复杂度,最差的情况下为O(n)(取决于匹配子串的长度),最理想的情况下为O(1);

2、indexOf方法

有多个重载的方法,参数可以为字符,也可以为字符串

 1     static int indexOf(char[] source, int sourceOffset, int sourceCount,
 2             char[] target, int targetOffset, int targetCount,
 3             int fromIndex) {
 4         if (fromIndex >= sourceCount) {
 5             return (targetCount == 0 ? sourceCount : -1);
 6         }
 7         if (fromIndex < 0) {
 8             fromIndex = 0;
 9         }
10         if (targetCount == 0) {
11             return fromIndex;
12         }
13
14         char first = target[targetOffset];
15         int max = sourceOffset + (sourceCount - targetCount);
16
17         for (int i = sourceOffset + fromIndex; i <= max; i++) {
18             /* Look for first character. */
19             if (source[i] != first) {
20                 while (++i <= max && source[i] != first);
21             }
22
23             /* Found first character, now look at the rest of v2 */
24             if (i <= max) {
25                 int j = i + 1;
26                 int end = j + targetCount - 1;
27                 for (int k = targetOffset + 1; j < end && source[j]
28                         == target[k]; j++, k++);
29
30                 if (j == end) {
31                     /* Found whole string. */
32                     return i - sourceOffset;
33                 }
34             }
35         }
36         return -1;
37     }

这个匹配子串的方法比较复杂,值得深入研究

3、substring方法

在JDK1.7之前的代码中,substring存在严重内存泄露问题,然而,这个问题在JDK1.7之后的版本中都有了改善;

因为JDK1.7中修改了构造方法,调用Arrays.copyOfRange()方法,只是复制出数组的一部分;

关于String类的构造方法,可以参看: JDK中String类的源码分析(一)

4、concat方法

连接两个字符串

 1     public String concat(String str) {
 2         int otherLen = str.length();
 3         if (otherLen == 0) {
 4             return this;
 5         }
 6         int len = value.length;
 7         char buf[] = Arrays.copyOf(value, len + otherLen);
 8         str.getChars(buf, len);
 9         return new String(buf, true);
10     }

5、split方法,切割字符串

 1     public String[] split(String regex, int limit) {
 2
 3         char ch = 0;
 4         if (((regex.value.length == 1 &&
 5              ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
 6              (regex.length() == 2 &&
 7               regex.charAt(0) == ‘\\‘ &&
 8               (((ch = regex.charAt(1))-‘0‘)|(‘9‘-ch)) < 0 &&
 9               ((ch-‘a‘)|(‘z‘-ch)) < 0 &&
10               ((ch-‘A‘)|(‘Z‘-ch)) < 0)) &&
11             (ch < Character.MIN_HIGH_SURROGATE ||
12              ch > Character.MAX_LOW_SURROGATE))
13         {
14             int off = 0;
15             int next = 0;
16             boolean limited = limit > 0;
17             ArrayList<String> list = new ArrayList<>();
18             while ((next = indexOf(ch, off)) != -1) {
19                 if (!limited || list.size() < limit - 1) {
20                     list.add(substring(off, next));
21                     off = next + 1;
22                 } else {    // last one
23                     //assert (list.size() == limit - 1);
24                     list.add(substring(off, value.length));
25                     off = value.length;
26                     break;
27                 }
28             }
29             // If no match was found, return this
30             if (off == 0)
31                 return new String[]{this};
32
33             // Add remaining segment
34             if (!limited || list.size() < limit)
35                 list.add(substring(off, value.length));
36
37             // Construct result
38             int resultSize = list.size();
39             if (limit == 0)
40                 while (resultSize > 0 && list.get(resultSize - 1).length() == 0)
41                     resultSize--;
42             String[] result = new String[resultSize];
43             return list.subList(0, resultSize).toArray(result);
44         }
45         return Pattern.compile(regex).split(this, limit);
46     }

6、trim方法,去除字符串两端的空格

 1     public String trim() {
 2         int len = value.length;
 3         int st = 0;
 4         char[] val = value;    /* avoid getfield opcode */
 5
 6         while ((st < len) && (val[st] <= ‘ ‘)) {
 7             st++;
 8         }
 9         while ((st < len) && (val[len - 1] <= ‘ ‘)) {
10             len--;
11         }
12         return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
13     }

算法时间复杂度在O(log(n))左右,截取,创建一个新的字符串;

总结:

在String类中的大多数方法,都存在new对象的操作,因为String的不可变性,如果大量的调用这些方法,在内存中会产生大量的String对象;

这样对GC的压力很非常大,很可能会出现内存溢出;

时间: 2024-12-05 23:25:26

JDK中String类的源码分析(二)的相关文章

关于java中ReentrantLock类的源码分析以及总结与例子

一,官方描述 关于ReentrantLock的官方描述,英文的就不贴出来了,这里我只贴出我自己翻译的描述: reentrant是一个跟synchronized具有相同行为和语义的持有锁来访问方法和语句的互斥锁,但是reentrant还拥有被扩展的能力. ReentrantLock会被线程拥有并且持续锁定,不会解锁.线程调用lock()方法返回后,则成功持有锁,否则这个锁正在被另一个线程所持有,只能等待另一个线程释放锁,如果当前线程拥有了锁,则调用lock()方法会立即返回,这个状态可以通过isH

String类常用方法源码分析

环境:JDK8 主要分析String类的一些常用的方法源码. String 先看String类的定义: public final class String    implements java.io.Serializable, Comparable<String>, CharSequence 可以看到String类被final修饰,因此不能被继承.String类还实现了序列化接口Serializable.可比较的接口Comparable并指定范型为String,该接口必须要实现int comp

Netty中NioEventLoopGroup的创建源码分析

NioEventLoopGroup的无参构造: 1 public NioEventLoopGroup() { 2 this(0); 3 } 调用了单参的构造: 1 public NioEventLoopGroup(int nThreads) { 2 this(nThreads, (Executor)null); 3 } 继续看到双参构造: 1 public NioEventLoopGroup(int nThreads, Executor executor) { 2 this(nThreads,

【小白的java成长系列】——顶级类Object源码分析

首先来说一下api文档使用,api这个词对有一定开发经验的java编程人员来说是很喜爱的~ java当然也提供了api开发文档,下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 找到下面的: 下载自己喜爱的版本即可,解压,点击~/jdk-7u60-apidocs/api/index.html就可以查看其api了: 跟上网一样一样的,点击相应链接就可以查看其信息了. 进入正题,说说Object这个类: 先

Java中arraylist和linkedlist源码分析与性能比较

Java中arraylist和linkedlist源码分析与性能比较 1,简介 在java开发中比较常用的数据结构是arraylist和linkedlist,本文主要从源码角度分析arraylist和linkedlist的性能. 2,arraylist源码分析 Arraylist底层的数据结构是一个对象数组,有一个size的成员变量标记数组中元素的个数,如下图: * The array buffer into which the elements of the ArrayList are sto

netty 源码分析二

以服务端启动,接收客户端连接整个过程为例分析, 简略分为 五个过程: 1.NioServerSocketChannel 管道生成, 2.NioServerSocketChannel 管道完成初始化, 3.NioServerSocketChannel注册至Selector选择器, 4.NioServerSocketChannel管道绑定到指定端口,启动服务 5.NioServerSocketChannel接受客户端的连接,进行相应IO操作 Ps:netty内部过程远比这复杂,简略记录下方便以后回忆

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

[Android]Fragment源码分析(二) 状态

我们上一讲,抛出来一个问题,就是当Activity的onCreateView的时候,是如何构造Fragment中的View参数.要回答这个问题我们先要了解Fragment的状态,这是Fragment管理中非常重要的一环.我们先来看一下FragmentActivity提供的一些核心回调: @Override protected void onCreate(Bundle savedInstanceState) { mFragments.attachActivity(this, mContainer,

JAVA Collection 源码分析(二)之SubList

昨天我们分析了ArrayList的源码,我们可以看到,在其中还有一个类,名为SubList,其继承了AbstractList. // AbstractList类型的引用,所有继承了AbstractList都可以传进来 private final AbstractList<E> parent; // 这个是其实就是parent的偏移量,从parent中的第几个元素开始的 private final int parentOffset; private final int offset; int s