【问题标题】:Memory efficient method String suffix节省内存的方法 字符串后缀
【发布时间】:2016-01-04 18:33:27
【问题描述】:

我的任务是创建一个内存高效方法,该方法采用由数字组成的String 并删除所有开头的零。

例如“001112”变成“1112”。

public static String hej (String v)
{
    StringBuilder    h = new StringBuilder(v);
    while(true)
    {
        if (h.charAt(0) == '0')
            h.deleteCharAt(0);
        else
            break;
    }
    return h.toString();
}

这是我的解决方案。当然它可以工作,但我的问题是,使用StringBuilder 是内存效率高还是使用字符串本身更有效,例如v.substring() 找不到太多关于什么更有效的信息。如果有人有一些文档的链接,请分享它们。

干杯

【问题讨论】:

  • 当您到达一个非 '0' 的字符时,您可以使用子字符串返回字符串的其余部分,这样您就不必创建 stringbuilder 对象。
  • StringBuilder 类是处理字符串时最推荐的方法。
  • @user3284549 是的,我知道。虽然问题仍然存在。哪一个会更有效率? StringBuilder 似乎更能适应变化,但它是否比你建议的方式消耗更多的空间?
  • 您可以随时查看两者的实现吗? jvm源代码可在线获取。
  • 最有效的方法是使用input.substring(<first index of nonzero char>),使用简单的for循环预先计算索引

标签: java string memory


【解决方案1】:

使用String.substring(int) 方法会占用最少的内存

public static String hej(String input)
{
    int i;
    for(i = 0; i < input.length(); i++)
        if(input.charAt(i) != '0')
            break;
    return input.substring(i);
}

源代码来自String

public String substring(int beginIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    int subLen = value.length - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}

这会调用String(char[], int, int) 构造函数

public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count <= 0) {
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        if (offset <= value.length) {
            this.value = "".value;
            return;
        }
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

使用StringBuilder 会占用一点内存来创建StringBuilder 以适应输入的大小,而使用String.substring(int) 只会占用表示修改后的输入所需的内存

【讨论】:

  • 这个答案确实非常好。最后一个解释非常好,因为我真的没有在那种情况下考虑过。猜猜我混淆了内存和性能!真的非常感谢!
  • 当你说“来自String的源代码”时,你指的是哪个Java实现?
  • @PeterSW Oracle 的实现,1.8.0_65
【解决方案2】:

如果您的字符串有 n 数量的前导零,那么使用 String 而不是 StringBuilder 将消耗 n 倍的内存。您知道,每当其中一些 char 发生更改时,String 都会在内存中创建一个新空间,因此 StringBuilder 是要走的路。

记住

每个字符串生成器都有容量。只要长度 字符串生成器中包含的字符序列不超过 容量,没有必要分配新的内部缓冲区。如果 内部缓冲区溢出,自动变大。

Oracle Docs

所以

字符串

String 是不可变的(一旦创建就不能更改)对象。这 作为字符串创建的对象存储在常量字符串池中。 Java 中的每个不可变对象都是线程安全的,这意味着 String 是 也是线程安全的。字符串不能被两个线程使用 同时。字符串一旦分配就不能更改。

字符串演示 = "你好"; // 上面的对象存储在常量中 字符串池及其值不可修改。

demo="再见" ; //在常量池中创建新的“Bye”字符串并且 由演示变量//“hello”字符串引用 存在于字符串常量池中并且它的值没有被覆盖但是我们 丢失了对“hello”字符串的引用

字符串缓冲区

StringBuffer 是可变的意味着可以改变对象的值。 通过 StringBuffer 创建的对象存储在堆中。 StringBuffer 具有与 StringBuilder 相同的方法,但每个 StringBuffer 中的方法是同步的,即 StringBuffer 是线程 安全的 。

因此它不允许两个线程同时访问 同样的方法。每个方法一次只能被一个线程访问 .

但是线程安全也有缺点,因为 由于线程安全属性,StringBuffer 命中。因此 StringBuilder 是 调用每个的相同方法时比 StringBuffer 更快 类。

StringBuffer 的值是可以改变的,也就是说可以赋值给 新价值。现在它是一个最常见的面试问题, 上述类之间的区别。字符串缓冲区可以转换 使用 toString() 方法到字符串。

StringBuffer demo1 = new StringBuffer("Hello") ; // 上面的对象 存储在堆中,其值可以更改。演示1=新 StringBuffer("再见"); // 上面的语句是正确的,因为它修改了 StringBuffer 中允许的值

Java Hungry

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-11-15
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多