2015-01-17 2 views
8

Я изучаю шаблон Decorator и разработал простой класс ToUpperCaseInputStream. Я перепробовал метод read(), чтобы он мог преобразовать все символы из InputStream в верхний регистр. Код метода показано ниже (броски OutOfMemoryError):OutOfMemoryError: пространство кучи Java при литье числового примитива в char

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

Как я понял позже, отбрасывая на символ является излишним, но это не главное. У меня "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 в результате преобразования бокс(§5.1.7).

кажется, что Autoboxing используется, но, как для меня это не так. Оба варианта одного и того же метода приводят к 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); 
    } 
} 

}

Что она делает это просто печатает простое сообщение из одного файла в другой.

Хотя этот вопрос решен, я хочу поделиться действительно хорошим объяснением того, как делается литье. https://stackoverflow.com/a/24637624/1923644

+0

Это должно быть совпадение. Две версии идентичны. – chrylis

+0

* "Когда я удаляю кастинг из задания и изменяю тип примитива переменной от char до int, код запускается без ошибок ... оба метода приводят к OutOfMemoryException" * Пожалуйста, отредактируйте вопрос, чтобы нам было ясно, какие броски и что не. – Radiodef

+0

@Radiodef сделано. – Zarial

ответ

4

Перед тем, как наложить на символ, вам необходимо проверить -1 (сигнализация окончания входных данных).

char в Java - это символ без знака, означающий, что при возврате -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); 
} 
+0

Вы меня неправильно поняли. Ваш код работает нормально, как предполагалось, но когда я добавляю такие кастинги: int c = (char) super.read(); все сбой ... – Zarial

+1

Вы не можете выполнить проверку перед -1. После каста вы никогда не получите -1, потому что символ всегда положительный. – yurgis

+0

Итак, строка «int i = (char) -1;» всегда приводит к max char? – Zarial