Search code examples
javaweak-referencesweakhashmap

Java WeakHashMap reference not being updated


In the code below I create a Pen object and initialize it's color to white. In the constructor of Pen, after setting the field 'penColor' to the value passed into the constructor, I update a global static weak hashmap that I'm keeping where the KEY is the 'this pointer - in my case a Pen, and the value is another weakhashmap whose KEY is the string "penColor" and whose value is a reference to the penColor member field.

Next, my code updates the Pen's color with a call to the Pen's setColor function. I would have thought that after this update, if I looked up the Pen object's color field in my weakhashmap, it would reflect the new color, but it does not. Can someone explain why that is?

package weakhashmaptest;


import java.awt.Color;
import java.util.WeakHashMap;
import java.util.Iterator;

public class Main {

    static WeakHashMap <Object, WeakHashMap>ownerMap = new WeakHashMap<Object, WeakHashMap>();

    public static void main(String[] args) {

        Pen r = new Pen(Color.WHITE);

        Iterator i = ownerMap.keySet().iterator();

        while(i.hasNext()) {
            Object key = i.next();
            System.out.println("\telement of hashmap is : " +ownerMap.get(key));
        }

        r.setColor(Color.BLACK);

        System.gc();

        i = ownerMap.keySet().iterator();

        while(i.hasNext()) {
            Object key = i.next();
            System.out.println("\telement of hashmap is : " +ownerMap.get(key));
        }

    }

    public static void mapUpdate(Object owner, Object reference, String field_name) {

        WeakHashMap reference_map = ownerMap.get(owner);

        if (reference_map == null) {         
            reference_map = new WeakHashMap();
            reference_map.put(field_name, reference);
        } else {         
            reference_map.put(field_name, reference);
        }

        ownerMap.put(owner, reference_map);

    }

}

class Pen {

    Color penColor;

    public Pen(Color c) {

        penColor = c;
        Main.mapUpdate(this, penColor, "penColor");

    }

    public void setColor(Color c) {

        penColor = c;

    }

}

Solution

  • You're putting a reference to the Color object into the map, rather than the Pen. If you put the Pen into the map, and then asked for the pen's colour later on, you'd see the change.

    To put it in very simplistic terms, what you're doing is similar to:

    Pen pen = new Pen(Color.WHITE);
    Color color = pen.penColor;
    pen.setColor(Color.BLACK);
    // color here still refers to Color.WHITE, not Color.BLACK.