Java CharAt() and deleteCharAt() performance
我一直想知道java中String / StringBuilder / StringBuffer的charAt函数的实现
它的复杂性是什么?
还有StringBuffer / StringBuilder中的deleteCharAt()呢?
对于
对于
让我们依次查看这些方法中的每一个的相应的实际Java实现(仅相关代码)。这本身将回答他们的效率。
String.charAt:
1 2 3 4 5 6 | public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; } |
如我们所见,这只是一个单一数组访问,这是一个恒定时间的操作。
StringBuffer.charAt:
1 2 3 4 5 | public synchronized char charAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); return value[index]; } |
同样,单阵列访问,因此是恒定时间的操作。
StringBuilder.charAt:
1 2 3 4 5 | public char charAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); return value[index]; } |
同样,单阵列访问,因此是恒定时间的操作。即使这三种方法看起来都一样,也存在一些细微的差异。例如,仅StringBuffer.charAt方法被同步,而其他方法则不同步。同样,如果检查String.charAt是否略有不同(猜为什么)。仔细研究这些方法实现本身会给我们带来其他小的差异。
现在,让我们看一下deleteCharAt的实现。
字符串没有deleteCharAt方法。原因可能是它是一个不变的对象。因此,公开一个明确指示该方法修改对象的API可能不是一个好主意。
StringBuffer和StringBuilder都是AbstractStringBuilder的子类。这两个类的deleteCharAt方法将实现委派给其父类本身。
StringBuffer.deleteCharAt:
1 2 3 4 | public synchronized StringBuffer deleteCharAt(int index) { super.deleteCharAt(index); return this; } |
StringBuilder.deleteCharAt:
1 2 3 4 | public StringBuilder deleteCharAt(int index) { super.deleteCharAt(index); return this; } |
AbstractStringBuilder.deleteCharAt:
1 2 3 4 5 6 7 | public AbstractStringBuilder deleteCharAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); System.arraycopy(value, index+1, value, index, count-index-1); count--; return this; } |
仔细研究AbstractStringBuilder.deleteCharAt方法可以发现它实际上是在调用System.arraycopy。在最坏的情况下,该值为O(N)。因此deleteChatAt方法的时间复杂度为O(N)。
假设您要从
从理论上讲,
- 它需要更多的空间,用于表示间隙在哪里的属性以及间隙本身。
-
它使代码复杂得多,并且减慢了其他操作的速度。例如,
charAt 必须将offset 与间隙的起点和终点进行比较,并在获取字符数组元素之前对实际的索引值进行相应的调整。 - 如果应用程序在同一缓冲区上执行多次插入/删除操作,这只会有所帮助。
毫不奇怪,这种"优化"尚未在标准
众所周知,字符串在JDK中作为字符数组实现,该数组实现了