Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: temporary commit

...

Code Block
bgColor#ffcccc
public class Widget {
    private int noOfComponents;
    public Widget(int noOfComponents) {
        this.noOfComponents = noOfComponents;
    }
    public int getNoOfComponents() {
        return noOfComponents;
    }
    public final void setNoOfComponents(int noOfComponents) {
        this.noOfComponents = noOfComponents;
    }

	// Also overrides hashCode() (code is omitted) ...

    public boolean equals(Object o) {
        if (o == null || !(o instanceof Widget)) {
            return false;
        }
        Widget widget = (Widget) o;
        // check for negative components
return this.noOfComponents == widget.getNoOfComponents();
    }
    @Override
 if (noOfComponents < 0public || widget.getNoOfComponentsint hashCode() < 0) {
        int res =  return false31;
        }
res = res * 17 +   noOfComponents;
        return this.noOfComponents == widget.getNoOfComponents()res;
    }
}

public class LayoutManager {
    private Set<Widget> layouts = new HashSet<Widget>();
    public void addWidget(Widget widget) {
        if (!layouts.contains(widget)) {
            layouts.add(widget);
        }
    }
    public int getLayoutSize() {
        return layouts.size();
    }
}

...

Code Block
public class Navigator extends Widget {
    public Navigator(int noOfComponents) {
        super(noOfComponents);
    }
    @Override
    public booleanint equalshashCode(Object o) {
		// Always returns true
        int res = 31;
        res = res * 17;
        return trueres;
    }
}

...

Client code

Code Block
        Widget nav = new Navigator(-1);
        Widget widget = new Widget(101);
        LayoutManager manager = new LayoutManager();
        manager.addWidget(nav);
        manager.addWidget(widget);
        System.out.println(manager.getLayoutSize()); // prints 2

The set layouts is expected to contain just one item because the number of components for both the navigator and widget being added is 1. However, the getLayoutSize() method returns 2.

The reason for this discrepancy is that the equalsthe hashCode() method of Widget is not used; instead the equalsused only once. When the navigator is added, the hashCode() method provided by the Navigator class is used. 

Compliant Solution (final class)

This compliant solution declares the Widget class final so that its methods cannot be overridden.

Code Block
bgColor#ccccff
public final class Widget {
    // ...
}

Noncompliant Code Example (run())

What gets printed - main or child / both / either ?

In this noncompliant code example, class Worker starts a thread in startThread()method.

code
Code Block
bgColor#ffcccc
public class TrustedWorker implements Runnable {
    TrustedWorker() { }

    public void startThread(String name) {
        new Thread(this, name).start();
    }

    @Override
    public void run() {
        System.out.println("ChildParent");
    }
}

public class UntrustedSubWorker extends TrustedWorker {
	// Note untrusted code may@Override
 start a new threadpublic even during construction
    Untrustedvoid startThread(String name) {
        super.startThread(name);
		new Thread(this, name).start();        
    }

    @Override
    public void run() {
        System.out.println("MainChild");
    }

}

Client code:

Code Block
Trusted a    Worker w = new UntrustedSubWorker();
    w.startThread("Mainthread");
a.run();

The programmer expects Parent and Child to be printed, however, Child is printed twice. This is because the overridden method run() is invoked both the times when a new thread is started.