To illustrate the concept with a quick (crude) example, consider the following:
public interface ChangeHandler {
public void handleChange();
}
public class FileMonitor {
private File file;
private Set<ChangeHandler> handlers = new HashSet<ChangeHandler>();
public FileMonitor(File file) {
this.file = file;
}
public void registerChangeHandler(ChangeHandler handler) {
this.handlers.add(handler);
}
public void unregisterChangeHandler(ChangeHandler handler) {
this.handlers.remove(handler);
}
...
}
If a client class then uses this FileMonitor API, they might do this:
public class MyClass {
File myFile = new File(...);
FileMonitor monitor = new FileMonitor(myFile);
public void something() {
...
ChangeHandler myHandler = getChangeHandler();
monitor.registerChangeHandler(myHandler);
...
}
}
If the author of the MyClass then forgets to call unregisterChangeHandler() when it's done with the handler, the FileMonitor's HashSet will forever reference the instance that was registered, causing it to remain in memory until the FileMonitor is destroyed or the application quits.
To prevent this, Bloch is suggesting using a weak-referencing collection instead of the HashSet, so that if your instance of MyClass is destroyed, the reference will be removed from the monitor's collection.
You might replace the HashSet in FileMonitor with a WeakHashMap and use the handlers as the keys, since the latter will automatically remove the handler from the collection when all other references to the object are gone.