创建一个特定大小(以MB为单位)的Java变量(字符串)。

23

我正在尝试对一些代码进行基准测试。我要通过套接字发送一个字符串消息。我想发送大小为100KB、2MB和10MB的字符串变量。有没有一种简单的方法来创建这些大小的变量?

目前我是这样做的。

private static String createDataSize(int msgSize) {
    String data = "a";
    while(data.length() < (msgSize*1024)-6) {
        data += "a";
    }
    return data;
}

但是这需要很长时间,有更好的方法吗?

更新: 谢谢,我现在正在这样做。

/**
 * Creates a message of size @msgSize in KB.
 */
private static String createDataSize(int msgSize) {
    // Java chars are 2 bytes
    msgSize = msgSize/2;
    msgSize = msgSize * 1024;
    StringBuilder sb = new StringBuilder(msgSize);
    for (int i=0; i<msgSize; i++) {
        sb.append('a');
    }
    return sb.toString();
  }

1
一个细节:String.length() 返回字符串中字符的数量。在网络上占用多少字节也取决于使用哪种编码方式。 - meriton
1
为什么char不必是2个字节,而只需要1个字节: https://dev59.com/DG445IYBdhLWcg3wBVzz - user3671433
5个回答

38

你可以简单地创建一个大字符数组。

char[] data = new char[1000000];

如果您需要创建一个真实的 String 对象,您可以:

String str = new String(data);

不要在循环中使用+=来构建字符串。这会导致O(n²)的内存和时间使用,因为String对象是不可变的(所以每次调用+=时,都必须创建一个新的String对象,在此过程中复制旧字符串的全部内容)。


30

使用 char[] 直接创建字符串,或者用它来构建字符串。

char[] chars = new char[size];
Arrays.fill(chars, 'a');

String str = new String(chars);

另外请注意,一个字符在内部占用两个字节。字符串通过网络传输时的长度取决于编码方式(不过字母"a"应该只占用一个字节)。


3
您可以使用Arrays.fill(chars, 'a')。 :-) - C. K. Young

27

Java中的char大小为2个字节(16位无符号)。因此,如果您想要2MB,则需要一百万个字符。您的代码存在两个明显的问题:

  1. 重复调用length()是不必要的。向Java String添加任何字符,其长度都会增加1,无论该字符是什么。也许您将其与字节大小混淆了,但它并不意味着字节大小。
  2. 您的代码存在严重的内存碎片问题。

进一步解释一下第二点,Java中的字符串连接操作符(+)会创建一个新的String,因为Java中的String是不可变的。因此:

String a = "a";
a += "b";

实际上意味着:

String a = "a";
String a = a + "b";

有时这会让以前的C ++程序员感到困惑,因为在C ++中字符串的工作方式不同。

所以您的代码实际上是为一个大小为一百万的消息分配了一百万个字符串。只有最后一个被保留。其他的都是垃圾,虽然会被清理,但没有必要。

一个更好的版本是:

private static String createDataSize(int msgSize) {
  StringBuilder sb = new StringBuilder(msgSize);
  for (int i=0; i<msgSize; i++) {
    sb.append('a');
  }
  return sb.toString();
}

关键区别在于:

  1. StringBuilder是可变的,因此不需要在每次更改时重新分配内存;
  2. 在此代码示例中,StringBuilder被预先分配到正确的大小。

注意:敏锐的读者可能已经注意到我已经做了:

sb.append('a');

而不是:

sb.append("a");

'a' 当然是一个单字符,"a" 是一个String。在这种情况下,您可以使用任何一种。

但是,并不是那么简单,因为它取决于字节如何编码。通常,除非另有指定,否则将使用可变宽度字符的UTF8。因此,一百万个字符的大小可能在1MB到4MB之间,具体取决于您最终编码的方式,而您的问题没有包含这方面的详细信息。

如果您需要特定大小的数据并且数据并不重要,我的建议是简单地使用正确大小的byte数组。


Java 字符串是不可变的,所以每个 += 实际上都通过复制先前字符串的整个内容来创建一个新的字符串。(我猜你提到的“巨大内存碎片问题”就是指这个。) - C. K. Young
在for循环中,我认为你的意思是sb.append('a');代码运行得非常好!谢谢。 - Bernie Perez

3
如果您正在使用Java 11,您可以使用String.repeat:
"a".repeat(20000);

0

是的,有的。可以使用缓冲字符串对象:

StringBuilder stringB = new StringBuilder(2000000); //for the 2mb one
String paddingString = "abcdefghijklmnopqrs";

while (stringB.length() + paddingString.length() < 2000000)
 stringB.append(paddingString);

//use it
stringB.toString()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接