2015-01-17 31 views
8

Ho studiato il pattern Decorator e ho sviluppato la classe semplice ToUpperCaseInputStream. Ho scavalcato il metodo read() in modo che potesse convertire tutti i caratteri da InputStream in maiuscolo. Codice del metodo è mostrato di seguito (getta OutOfMemoryError):OutOfMemoryError: spazio heap Java durante il casting di una primitiva numerica in char

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

Come ho capito dopo, gettando a char è ridondante, ma non è questo il punto. Sto avendo "java.lang.OutOfMemoryError: spazio heap Java" quando il codice:

((char) super.read()) 

Esamina. Per rendere questo più semplice che ho scritto lo stesso metodo (questo getta OutOfMemoryError):

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

E questo non lo fa:

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

quando rimuovo colata dalla cessione il codice viene eseguito senza errori e risultati in tutto il testo in maiuscolo. Come si dice in esercitazioni Oracle:

La cessione di componente di un campo di tipo di riferimento (§15.26.1), una chiamata di metodo espressione (§15.12), o un prefisso o suffisso incremento (§15.14. 2, §15.15.1) o l'operatore di decremento (§15.14.3, §15.15.2) possono tutti gettare un OutOfMemoryError a seguito della conversione di pugilato(§5.1.7).

sembra che autoboxing viene utilizzato, ma come per me non è il caso. Entrambe le varianti dello stesso metodo generano OutOfMemoryError. Se sbaglio, ti prego di spiegarmelo, perché mi farà saltare in aria la testa.

Per fornire maggiori informazioni c'è il codice del client:

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

}

Ciò che fa è stampato solo semplice messaggio da un file all'altro.

Anche se il caso è risolto, voglio condividere una spiegazione molto buona di come è fatto il casting. https://stackoverflow.com/a/24637624/1923644

+0

che è avuto modo di essere una coincidenza. Le due versioni sono identiche. – chrylis

+0

* "quando rimuovo il casting dall'assegnazione e cambio il tipo di variabile primitiva da char a int, il codice viene eseguito senza errori ... entrambi i metodi generano OutOfMemoryException" * Si prega di modificare la domanda in modo che sia chiaro a noi cosa getta e cosa non. – Radiodef

+0

@Radiodef terminato. – Zarial

risposta

4

Prima di eseguire il cast, è necessario verificare la presenza di -1 (segnalazione della fine dei dati di input).

char in Java è un corto senza segno, il che significa che quando viene restituito -1, il cast lo renderà 65535. Anche se non hai OutOfMemory, il tuo codice è ancora rotto.

Per quanto riguarda il motivo per cui si ottiene l'errore OOM, è difficile dire senza codice completo, forse, più avanti nel codice ci sono alcune allocazioni di memoria in base al valore del personaggio.

in modo da provare questo e vedere se aiuta:

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

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

Mi hai frainteso. Il tuo codice funziona correttamente come previsto, ma quando aggiungo casting in questo modo: int c = (char) super.read(); tutto si blocca ... – Zarial

+1

Non puoi eseguire il cast prima di controllare -1. Dopo il cast non otterrai mai -1 perché il char è sempre positivo. – yurgis

+0

Quindi la riga "int i = (char) -1;" porta sempre a max char? – Zarial