OutOfMemoryError:将数值原语强制转换为字符时的Java堆空间

OutOfMemoryError:将数值原语强制转换为字符时的Java堆空间,java,casting,out-of-memory,primitive,autoboxing,Java,Casting,Out Of Memory,Primitive,Autoboxing,我一直在研究Decorator模式,并开发了简单的类ToUpperCaseInputStream。我重写了read()方法,因此它可以将InputStream中的所有字符转换为大写。方法的代码如下所示(抛出OutOfMemoryError): 正如我后来发现的,转换为char是多余的,但这不是重点。当代码: ((char) super.read()) 评估。为了简化此过程,我编写了相同的方法(此方法抛出OutOfMemoryError): 而这一条没有: @Override public

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

正如我后来发现的,转换为char是多余的,但这不是重点。当代码:

((char) super.read())  
评估。为了简化此过程,我编写了相同的方法(此方法抛出OutOfMemoryError):

而这一条没有:

@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)的赋值由于装箱转换,所有可能会抛出OutOfMemory错误

似乎使用了自动装箱,但对我来说,情况并非如此。同一方法的两个变体都会导致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);
    }
}
}

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


虽然这个案子已经解决了,但我想分享一个关于铸造是如何完成的非常好的解释

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

Java中的char是一个无符号的缩写,这意味着当返回-1时,您的cast将变为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);
} 

那一定是巧合。这两个版本是相同的。“当我从赋值中删除强制转换并将变量原语类型从char更改为int时,代码运行时没有错误……两种方法都会导致OutOfMemoryException”请编辑此问题,以便我们清楚地知道哪些抛出,哪些不抛出。既然您添加了更多代码,@yurgis answer就有意义了。将
println
放入
while
中,查看在每种情况下执行的次数。我猜在第二种情况下,while条件总是满足的。尽管您更正了代码,但它仍然是错误的。演员阵容结束后,c永远不会-1检查:你误解了我。您的代码工作正常,但当我添加这样的强制转换时:int c=(char)super.read();一切都崩溃了…在检查-1之前你不能施放。在强制转换之后,您将永远不会得到-1,因为char始终为正数。因此,行“int i=(char)-1;”始终会得到max char?是的,请尝试以下代码{char c=0;c--;System.out.println(c);}有关无符号值的详细信息:
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);
    }
}
@Override
public int read() throws IOException {
    int c = super.read();
    if (c == -1) return c;

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