我有(显然是错误的?)印象,Java子串(srcArray,startIndex,endIndex)方法没有分配新内存,而是重用现有的底层char []数组。由于String的不变性,这种方法似乎是可能的。
然而,在实际查看JDK源代码时,我们发现以下内容:
public String substring(int beginIndex, int endIndex) {
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
public String(char value[], int offset, int count) {
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
请注意复制/复制内容的copyOfRange。
这样做的动机是使用非常大的数组来表示线性代数矩阵的后备存储。我们没有办法接受复制它们。但是,我希望有一个自定义表示支持数组的部分,以方便编程。但是,如果不执行数据复制,那将是合理的。与String的搭配是我研究了String如何处理无数据副本,并发现它们(在后来的java版本中显然是......)确实执行了副本。
那么,实际上有没有办法实现零拷贝?
答案 0 :(得分:17)
使用就是这样,但它被改变了; Java的设计者得出的结论是,它导致的问题多于解决的问题,特别是由于a)内存泄漏的风险,b)大多数substring
调用是针对相对较小的范围而复制成本低的事实
您可以做的最接近的事情是,CharSequence
无法复制String
的子范围,您可以写CharBuffer.wrap(string).subSequence(from, to)
。
答案 1 :(得分:1)
类java.nio.StringCharBuffer
在子字符串上实现这样的“视图”,而不复制字符串的基础char []数组。为了访问String数组,它使用String.charAt
函数以及内部偏移量(从String开头的字符偏移量)。
不幸的是,它是包私有的,不能直接使用。但是,超类java.nio.CharBuffer
是公共的,您可以使用java.nio.StringCharBuffer
所采用的相同方法来实现自己的StringCharBuffer实现。
请注意,如果您不执行此操作,而只是按照另一个答案的建议使用CharBuffer.wrap
,您仍然会复制一次数组。
或者,您可能只需要从某个索引开始的字符流。在这种情况下,您可以使用类似以下内容:
IntStream
.range(start, str.length())
.map(i -> str.charAt(i))
...
获取字符流。请注意,这与执行str.chars().skip(start)
不同,因为后者实际上会将光标前进1 start
次。
答案 2 :(得分:0)
public class Dring { // Double String
double[] array;
int length;
int offset;
// You probably want hash
public Dring(double[] data) {
array = new double[data.length];
<copy from data to array using your favorite array copy method>
length = data.length;
offset = 0;
}
private Dring(int offsetParm, int lengthParm, double[] data) {
array = data;
length = lengthParm;
offset = offsetParm
}
public Dring subDring(int offsetParm, int lengthParm) {
// Check parms
return new Dring(offset + offsetParm, lengthParm, array);
}
public double doubleAt(int index) {
// Check parm
return array[offset + index];
}
}