让我们依次看一下这些方法中每个方法的相应实际java实现(仅相关代码)。这本身将回答他们的效率。
String.charAt :
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
正如我们所看到的,它只是一个单数组访问,这是一个恒定的时间操作。
StringBuffer.charAt :
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
同样,单阵列访问,所以是一个恒定的时间操作。
StringBuilder.charAt :
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 :
public synchronized StringBuffer deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
StringBuilder.deleteCharAt :
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
AbstractStringBuilder.deleteCharAt :
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)时间复杂度。