[HashMap] Come ottenere il valore di questo field

di il
10 risposte

[HashMap] Come ottenere il valore di questo field

Buonasera,

Ho una classe di nome Tile che implementa una interfaccia di nome Drawable con un metodo Draw e getPosX().
Come accedo a getPosX dopo averlo memorizzato in una HashMap ?

Grazie mille

public class test {

    
    private int x;
    private int y;
    private int width  = 32;
    private int height = 32;
    private Integer index;
    
    HashMap <Integer, Object> hashMap;  

    public test() {
        
            hashMap = new  HashMap <Integer, Object>();
    
            hashMap.put(index, new Tile(x,y,width,height));
            Object value =  hashMap.get(index);
            
            System.out.print(value);  //getPosX();
                                       
    }
    public static void main(String[] args) {
        test test = new test();
    }
}

10 Risposte

  • Re: [HashMap] Come ottenere il valore di questo field

    Cyrano ha scritto:


    Come accedo a getPosX dopo averlo memorizzato in una HashMap ?
        HashMap <Integer, Object> hashMap;
    Perché <Integer,Object> e non (magari meglio) <Integer,Tile> ??
  • Re: [HashMap] Come ottenere il valore di questo field

    Son cotto , sry ! :)Grazie
  • Re: [HashMap] Come ottenere il valore di questo field

    Buongiorno ,

    Riprendo questo topic per non crearne un altro , la domanda è simile.
    Di seguito un metodo per fare il crop (32x32) di questa immagine Tileset.
    La prima volta che ho scritto il metodo , inserivo ogni subImagine dentro un oggetto Tile e poi collezionavo ogni oggetto Tile dentro una Lista.

    Addesso sto modificando il metodo per inserire ogni oggetto Tile dentro una HashMap con questi argomenti :
     ConcurrentHashMap <Shape, Tile> hashMap = new  ConcurrentHashMap <Shape, Tile>();
    il metodo della classe Game è questo :
    
     private BufferedImage[] getSubImages (BufferedImage bi){
                int col;
                int row;
                BufferedImage[] arrayBi;
                
                /* Initialize bounds object */
                bounds = new Rectangle(0,0,TILE_WIDTH,TILE_HEIGHT);
                
                col = bi.getWidth()/TILE_WIDTH;
                row = bi.getHeight()/TILE_HEIGHT;
                
                arrayBi = new BufferedImage[col*row];
                int index = 0;
                for(int i = 0; i < row; i++) {
                    int y= i*TILE_HEIGHT;
                        for(int j = 0; j < col; j++) {
                            int x = j*TILE_WIDTH;
                            
                            /* Gets subImage */
                            arrayBi[index++] = bi.getSubimage(x, y, TILE_WIDTH, TILE_HEIGHT);
                            
                            /* set bounds object */
                            bounds.x = x;
                            bounds.y = y;
                            
                            /* New object */
                            Tile tile = new Tile(bounds, TILE_WIDTH, TILE_HEIGHT,arrayBi[index]);
                            tile.setId(index);
                            hashMap.putIfAbsent(bounds, tile);
                            
                            /* debug  */ 
                            System.out.println(">>>>> "+ bounds.x + "," + bounds.y);
                        }
                }
                return arrayBi;
        }
    
    Ottengo l'Hash Table
    
      public ConcurrentHashMap <Shape, Tile> getTiles(){
            return hashMap;
        }    
    


    In un altra classe ho scritto due righe di test per ottenere il valore di un field ( getId come esempio).
    Vorrei capire come utilizzare l'oggetto bounds come Key nell'hashMap:

    Un codice di test dentro una classe di tipo Jpanel
    
       Rectangle r = new Rectangle (0,0,32,32);
        r.x = 32;
        r.y = 32;
        
        Game    = new Game(new File("tileset01.jpg"));
        hashMap = Game.getTiles();
           
       int id = hashMap.get(r).getId();   //<<--- NullPointerException 
       System.out.println("id: "+id);
    


    Con queste dichiarazioni all'inizio
    
      private Game Game;
      ConcurrentHashMap <Shape, Tile> hashMap = new  ConcurrentHashMap <Shape, Tile>();
    

    L'intenzione era di dare ad un Hashmap <k,v> , l'oggetto bounds a k come Key e ottenere di conseguenza l'oggetto corrispondente v
    Ottengo invece un errore di NullPointer , non sono sicuro se si riferisce all'HashMap o all'oggetto Tile.
    Forse il riferimento per la Key e sbagliato e quindi punta ad un oggetto Tile non esistente.
    Spero di non aver fatto qualche errore grossolano

    Secondo voi , si può fare?


    EDIT:
    Devo fare l' ovverride di equals() ?Sei si in quale classe ?
    Grazie
  • Re: [HashMap] Come ottenere il valore di questo field

    Cyrano ha scritto:


    
     private BufferedImage[] getSubImages (BufferedImage bi){
                
                /* Initialize bounds object */
                bounds = new Rectangle(0,0,TILE_WIDTH,TILE_HEIGHT);
                
                arrayBi = new BufferedImage[col*row];
                int index = 0;
                for(int i = 0; i < row; i++) {
                    int y= i*TILE_HEIGHT;
                        for(int j = 0; j < col; j++) {
                            int x = j*TILE_WIDTH;
                            
                            /* Gets subImage */
                            arrayBi[index++] = bi.getSubimage(x, y, TILE_WIDTH, TILE_HEIGHT);
                            
                            /* set bounds object */
                            bounds.x = x;
                            bounds.y = y;
    
                            hashMap.putIfAbsent(bounds, tile);
    
    Il problema è in questo codice sopra. Nota bene che l'oggetto Rectangle è UNO solo, quello che crei all'inizio. Dentro tutti i vari cicli, vai semplicemente a cambiargli sotto il naso i campi x/y. E quindi nella mappa fai il put con chiave che è sempre lo stesso Rectangle.
    Il punto è che facendo così ... fai casino. Quindi devi cambiare il codice sopra e non usare solo un Rectangle.
  • Re: [HashMap] Come ottenere il valore di questo field

    Se ho capito bene , devo instanziare n volte anche r, ovvero l'oggetto di tipo Rectangle.
    
                int index = 0;
                for(int i = 0; i < row; i++) {
                    int y = i * TILE_HEIGHT;
                        for(int j = 0; j < col; j++) {
                            int x = j*TILE_WIDTH;
                            
                            /* Gets subImage */
                            arrayBi[index++] = bi.getSubimage(x, y, TILE_WIDTH, TILE_HEIGHT);
                            
                            /* set bounds object */
                            bounds[index] = new Rectangle(x,y,TILE_WIDTH,TILE_HEIGHT);
                            
                            /* New object */
                            Tile tile = new Tile(bounds[index], TILE_WIDTH, TILE_HEIGHT,arrayBi[index]);
                            tile.setId(index);
                            
                            hashMap.putIfAbsent(bounds[index], tile);
                            
                            /* debug */
                            System.out.println(">>>>> "+bounds[index].x+","+bounds[index].y);
                        }
                }
    
    Sembra funzionare.Prima utilizzavo uno stesso oggetto r quindi era impossibile associare ogni paio di valori ad ogni oggetto Tile creato . tantomeno pretendere da hashMap un oggetto Tile chissà a quale coppia di x,y.

    Grazie questo codice dovrebbe insieme al resto essere in grado di identificare quale tile è stato cliccato senza fare il loop di tutti gli oggetti creati
    e disegnati su schermo presenti nella vecchia lista ( List)
  • Re: [HashMap] Come ottenere il valore di questo field

    Cyrano ha scritto:


    Se ho capito bene , devo instanziare n volte anche r, ovvero l'oggetto di tipo Rectangle.
    Sì. Comunque, se vogliamo fare i fini, nelle mappe si dovrebbero usare come chiavi degli oggetti "immutabili". E per ovvi buoni motivi: non sarebbe possibile cambiare lo stato di una chiave già nella mappa sotto il naso della mappa stessa ...
    Rectangle (quello di AWT) invece è mutabile (e molto ... oltretutto direttamente sui suoi field), quindi non è proprio il massimo come "chiave".
  • Re: [HashMap] Come ottenere il valore di questo field

    Capisco , ma non so come "unire" in un solo argomento due valori come x e y ed inserirli nella HashMap.

    Diversamente con una List sono costretto a creare un ciclo dove andare a leggere ogni coordinata x e y contenuta nell'oggetto Tile e confrontarle con le coordinate del mouse. Il fine è :

    - scegliere un tile da una toolBox per poi disegnare
    -Cancellare un tile da un disegno esistente che può contenere nel mio caso al massimo 1265 tile

    Con la lista è diventato semplice , ma è anche più lento.
    Ho pensato anche a dividere la porzione di schermo dedicata al disegno in quattro parti e quindi in quattro liste, ma mi sembra macchinoso

    Edit:
    Per mutabile intendi che posso cambiare il valore dei suoi field?

    Edit2:
    come non detto mi sto leggendo questo dal sito di oracle
    
    Immutable Objects
    
    An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is widely accepted as a sound strategy for creating simple, reliable code.
    
    Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state.
    
    Programmers are often reluctant to employ immutable objects, because they worry about the cost of creating a new object as opposed to updating an object in place. The impact of object creation is often overestimated, and can be offset by some of the efficiencies associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.
    
    The following subsections take a class whose instances are mutable and derives a class with immutable instances from it. In so doing, they give general rules for this kind of conversion and demonstrate some of the advantages of immutable objects
    
  • Re: [HashMap] Come ottenere il valore di questo field

    Cyrano ha scritto:


    Ho pensato anche a dividere la porzione di schermo dedicata al disegno in quattro parti e quindi in quattro liste, ma mi sembra macchinoso
    No, non scherziamo ....

    Cyrano ha scritto:


    Per mutabile intendi che posso cambiare il valore dei suoi field?
    Sì.

    Cyrano ha scritto:


    Edit2:
    come non detto mi sto leggendo questo dal sito di oracle
    Immutable Objects
    public class TileRect {
        private final int x;
        private final int y;
        private final int width;
        private final int height;
    
        // costruttore (riceve x, y ecc...)
        // metodi getter (NIENTE setter, i field sono final!)
        // equals e hashCode (e toString magari che è utile)
    }
  • Re: [HashMap] Come ottenere il valore di questo field

    Si però devo utilizzare lo stesso metodo per disegnare oltre che la toolbox ( oggetto che non varia la sua posizione dopo il costruttore, quindi va bene final)
    anche per il livello disegnato dall'utente. Mi rendo conto che come primo programma non è il massimo iniziare da un giochino 2D però è molto stimolante
    Il livello disegnato dall'utente ad un certo punto dovrà variare la posizione come un blocco unico , quindi ogni oggetto Tile che lo compone assumerà valori differenti per i suoi field x e y. Questo perchè la posizione del player determinerà un offset che verrà aggiunto ad ogni x e y del singolo tile
    (scrolling).Ho spiegato questo per fare un quadro della situazione , non per spiegarlo a te

    L'articolo di oracle , suggerisce final oppure metodi sincronizzati in caso sia presente più di un thread oppure per non rischiare di invocare quell'oggetto contemporaneamente..Ma non sembra una cosa semplice.
    Nel mio programma c'e solo un thread che viene lanciato all'inizio. Ora giustamente come mi hai suggerito devo capire se posso incorrere in questo problema.
    Tutto questo sempre se ho capito bene

    Edit:
    ConcurrentHashMap non dovrebbe risolvere il problema di una eventuale chiamata "concorrente" che andrebbe a modificare l'hashMap ?
    Pensandoci meglio , l'unica chiamata "concorrente" potrebbe essere quando faccio il rendering di tutti gli oggetti contenuti dentro l'hashMap ( ciclo for dentro un metodo draw quindi read) ed una possibile modifica ( write) quando devo cancellare un tile appartenente ad un livello disegnato
    non so se fila come ragionamento, e una cosa che sto studiando ora
  • Re: [HashMap] Come ottenere il valore di questo field

    Cyrano ha scritto:


    L'articolo di oracle , suggerisce final oppure metodi sincronizzati in caso sia presente più di un thread oppure per non rischiare di invocare quell'oggetto contemporaneamente..
    La sincronizzazione non centra nulla direttamente con la "immutabilità". La sincronizzazione serve principalmente per garantire "atomicità" e "visibilità delle modifiche" tra thread.
    Se un oggetto ha stato immutabile (o non ha alcun stato), intrinsecamente è thread-safe e non c'è bisogno di alcuna sincronizzazione su di esso.

    Cyrano ha scritto:


    Nel mio programma c'e solo un thread che viene lanciato all'inizio.
    A parte il Event Dispatch Thread di Swing, quello c'è comunque.
    Però allora .... perché ConcurrentHashMap?? Questa serve tipicamente quando c'è una ALTA concorrenza (parliamo di decine di thread che cercano di usare la mappa)

    Cyrano ha scritto:


    ConcurrentHashMap non dovrebbe risolvere il problema di una eventuale chiamata "concorrente" che andrebbe a modificare l'hashMap ?
    ConcurrentHashMap è thread-safe e può essere usata concorrentemente da più thread. Cioè ciascuno dei suoi metodi, preso singolarmente, è thread-safe.
    Poi è chiaro che se fai tu operazioni "composte", tipo faccio un get, modifico il valore, faccio un put, questo insieme di operazioni NON è "atomico" e non lo puoi rendere tale perché ConcurrentHashMap non offre alcun appiglio per fare del client side locking.
    Non a caso ConcurrentHashMap mette a disposizione operazioni composte particolari tipo putIfAbsent e da Java 8 computeIfAbsent, computeIfPresent, che altrimenti non si potrebbero fare esternamente.
Devi accedere o registrarti per scrivere nel forum
10 risposte