2015-01-17 15 views
8

Badam wzorzec dekoratora i opracowałem prostą klasę ToUpperCaseInputStream. Przepisałem metodę read(), aby przekonwertować wszystkie znaki z InputStream na wielkie litery. Kod metody wykazały poniżej (rzuca OutOfMemoryError):OutOfMemoryError: Przestrzeń sterty Java podczas rzutowania liczbowego prymitywu na char.

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

Jak Pomyślałem później, casting do char jest zbędny, ale to nie o to chodzi. Mam "java.lang.OutOfMemoryError: Java sterty przestrzeń", gdy kod:

((char) super.read()) 

ocenia. Aby uczynić to prostsze pisałem ten sam sposób (ten rzuca OutOfMemoryError):

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

A ten nie:

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

Kiedy usunąć odlew z cesją kod działa bez żadnych błędów i powoduje, że cały tekst jest pisany wielkimi literami. Jak to się mówi w ćwiczeń Oracle:

przypisania do składnik tablicą typu odniesienia (§15.26.1) sposób wywołania ekspresji (§15.12) lub przedrostek lub przyrostek przyrost (§15.14. 2, §15.15.1) lub operator zmniejszania (§15.14.3, §15.15.2) może wszystkie wyrzucać OutOfMemoryError wyniku konwersji boksu(§5.1.7).

wydaje się, że autoboxing jest stosowany, ale dla mnie tak nie jest. Oba warianty tej samej metody powodują OutOfMemoryError. Jeśli się mylę, proszę wyjaśnij mi to, ponieważ to rozwali moją głowę.

Aby zapewnić więcej informacji znajduje się kod klienta:

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); 
    } 
} 

}

Co robi jest po prostu drukuje prostą wiadomość z jednego pliku do drugiego.

Mimo że sprawa została rozwiązana, chcę podzielić się naprawdę dobrym wyjaśnieniem, w jaki sposób odbywa się casting. https://stackoverflow.com/a/24637624/1923644

+0

To musi być przypadek. Obie wersje są identyczne. – chrylis

+0

* "kiedy usuwam casting z przydziału i zmieniam typ zmiennej pierwotnej z char na int, kod działa bez błędów ... obie metody powodują OutOfMemoryException" * Proszę edytować pytanie, aby było dla nas jasne, co wyrzuca i co nie. – Radiodef

+0

@Radiodef done. – Zarial

Odpowiedz

4

Przed rzutowaniem na char należy sprawdzić wartość -1 (sygnalizacja końca danych wejściowych).

char w Javie to niepodpisany skrót, co oznacza, że ​​po zwróceniu -1, twoja obsada sprawi, że będzie to 65535. Nawet jeśli nie masz OutOfMemory, twój kod nadal jest uszkodzony.

Jeśli chodzi o błąd OOM, trudno powiedzieć bez pełnego kodu, może później w kodzie są pewne przydziały pamięci oparte na wartości znaku.

więc spróbować i zobaczyć, czy to pomaga:

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

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

Źle mnie zrozumiałeś. Twój kod działa poprawnie zgodnie z przeznaczeniem, ale kiedy dodaję takie przesyłanie: int c = (char) super.read(); wszystko zawiesza się ... – Zarial

+1

Nie możesz rzucić przed sprawdzeniem, czy -1. Po rzucie nigdy nie otrzymasz -1, ponieważ char jest zawsze dodatni. – yurgis

+0

Tak więc linia "int i = (char) -1;" zawsze skutkuje max char? – Zarial

Powiązane problemy