OutOfMemoryError:将数字基元转换为char时的Java堆空间

时间:2015-01-17 19:06:43

标签: java casting out-of-memory primitive autoboxing

我一直在研究Decorator模式并开发了简单的类ToUpperCaseInputStream。我重写了read()方法,因此它可以将所有字符从InputStream转换为大写。该方法的代码如下所示(抛出OutOfMemoryError):

@Override
public int read() throws IOException {
    return Character.toUpperCase((char)super.read());
}

正如我后面所说,转换为char是多余的,但这不是重点。代码时我有“java.lang.OutOfMemoryError:Java堆空间”:

((char) super.read())  

评估。为了使这更简单,我写了相同的方法(这个抛出OutOfMemoryError):

@Override
public int read() throws IOException {
    int c =(char) super.read();
    return (c == -1 ? c : Character.toUpperCase(c));
} 

这个不是:

@Override
public int read() throws IOException {
    int c = super.read();
    return (c == -1 ? c : Character.toUpperCase(c));
} 

当我从赋值中删除转换时,代码运行时没有错误,并导致所有文本都是大写的。正如在Oracle教程中所说:

赋予引用类型的数组组件(第15.26.1节),方法调用表达式(第15.12节)或前缀或后缀增量(§ 15.14.2,§15.15.1)或减量运算符(§15.14.3,§15.15.2)可能所有因拳击转换而抛出OutOfMemoryError {{ 3}}

似乎使用了自动装箱,但对我来说并非如此。同一方法的两种变体都会导致OutOfMemoryError。如果我错了,请向我解释一下,因为它会让我大吃一惊。

要提供更多信息,请提供客户端代码:

public class App {
public static void main(String[] args) throws IOException {

    try (InputStream inet = new ToUpperCaseInputStream(new FileInputStream("d:/TEMP/src.txt"));
        FileOutputStream buff = new FileOutputStream("d:/TEMP/dst.txt")) {
        copy(inet, buff);
    }
}

public static void copy(InputStream src, OutputStream dst) throws IOException {
    int elem;
    while ((elem = src.read()) != -1) {
        dst.write(elem);
    }
}

}

它的作用是将简单的消息从一个文件打印到另一个文件。

虽然案件已经解决,但我想分享关于如何完成施法的非常好的解释。 (§5.1.7).

1 个答案:

答案 0 :(得分:4)

在转换为char之前,您需要检查-1(输入数据的信号结束)。

Java中的char是一个unsigned short,这意味着当返回-1时,你的演员表会使它成为65535.即使你没有OutOfMemory,你的代码仍然会被破坏。

关于你为什么会收到OOM错误,很难说没有完整的代码,也许,稍后在代码中会有一些基于字符值的内存分配。

所以试试看看是否有帮助:

@Override
public int read() throws IOException {
    int c = super.read();
    if (c == -1) return c;

    char ch = (char) c;
    return Character.toUpperCase(ch);
}