JUnit theory for hashCode/equals contract - java

The following class serve as generic tester for equals/hashCode contract. It is a part of a home grown testing framework.
What do you think about?
How can I (strong) test this class?
It is a good use of Junit theories?
The class:
#Ignore
#RunWith(Theories.class)
public abstract class ObjectTest {
// For any non-null reference value x, x.equals(x) should return true
#Theory
public void equalsIsReflexive(Object x) {
assumeThat(x, is(not(equalTo(null))));
assertThat(x.equals(x), is(true));
}
// For any non-null reference values x and y, x.equals(y)
// should return true if and only if y.equals(x) returns true.
#Theory
public void equalsIsSymmetric(Object x, Object y) {
assumeThat(x, is(not(equalTo(null))));
assumeThat(y, is(not(equalTo(null))));
assumeThat(y.equals(x), is(true));
assertThat(x.equals(y), is(true));
}
// For any non-null reference values x, y, and z, if x.equals(y)
// returns true and y.equals(z) returns true, then x.equals(z)
// should return true.
#Theory
public void equalsIsTransitive(Object x, Object y, Object z) {
assumeThat(x, is(not(equalTo(null))));
assumeThat(y, is(not(equalTo(null))));
assumeThat(z, is(not(equalTo(null))));
assumeThat(x.equals(y) && y.equals(z), is(true));
assertThat(z.equals(x), is(true));
}
// For any non-null reference values x and y, multiple invocations
// of x.equals(y) consistently return true or consistently return
// false, provided no information used in equals comparisons on
// the objects is modified.
#Theory
public void equalsIsConsistent(Object x, Object y) {
assumeThat(x, is(not(equalTo(null))));
boolean alwaysTheSame = x.equals(y);
for (int i = 0; i < 30; i++) {
assertThat(x.equals(y), is(alwaysTheSame));
}
}
// For any non-null reference value x, x.equals(null) should
// return false.
#Theory
public void equalsReturnFalseOnNull(Object x) {
assumeThat(x, is(not(equalTo(null))));
assertThat(x.equals(null), is(false));
}
// Whenever it is invoked on the same object more than once
// the hashCode() method must consistently return the same
// integer.
#Theory
public void hashCodeIsSelfConsistent(Object x) {
assumeThat(x, is(not(equalTo(null))));
int alwaysTheSame = x.hashCode();
for (int i = 0; i < 30; i++) {
assertThat(x.hashCode(), is(alwaysTheSame));
}
}
// If two objects are equal according to the equals(Object) method,
// then calling the hashCode method on each of the two objects
// must produce the same integer result.
#Theory
public void hashCodeIsConsistentWithEquals(Object x, Object y) {
assumeThat(x, is(not(equalTo(null))));
assumeThat(x.equals(y), is(true));
assertThat(x.hashCode(), is(equalTo(y.hashCode())));
}
// Test that x.equals(y) where x and y are the same datapoint
// instance works. User must provide datapoints that are not equal.
#Theory
public void equalsWorks(Object x, Object y) {
assumeThat(x, is(not(equalTo(null))));
assumeThat(x == y, is(true));
assertThat(x.equals(y), is(true));
}
// Test that x.equals(y) where x and y are the same datapoint instance
// works. User must provide datapoints that are not equal.
#Theory
public void notEqualsWorks(Object x, Object y) {
assumeThat(x, is(not(equalTo(null))));
assumeThat(x != y, is(true));
assertThat(x.equals(y), is(false));
}
}
usage:
import org.junit.experimental.theories.DataPoint;
public class ObjectTestTest extends ObjectTest {
#DataPoint
public static String a = "a";
#DataPoint
public static String b = "b";
#DataPoint
public static String nullString = null;
#DataPoint
public static String emptyString = "";
}

One thing to consider: testing an object's conformance to the equals contract should involve instances of other types. In particular, problems are likely to appear with instances of a subclass or superclass. Joshua Bloch gives an excellent explanation of the related pitfalls in Effective Java (I'm reusing duffymo's link, so he should get credit for it) -- see the section under Transitivity involving the Point and ColorPoint classes.
True, your implementation doesn't prevent someone from writing a test that involves instances of a subclass, but because ObjectTest is a generic class it gives the impression that all data points should come from a single class (the class being tested). It might be better to remove the type parameter altogether. Just food for thought.

Joshua Bloch lays out the contract for hash code and equals in chapter 3 of "Effective Java". Looks like you covered a great deal of it. Check the document to see if I missed anything.

Maybe I'm missing something, but the equalsIsSymmetric test is in fact only correctly tested if you have to DataPoints which have the same values (e.g. String a = "a"; String a2 = "a";)
Otherwise this test is only done when the 2 parameters are one instance (i.e. equalsIsSymmetric(a, a);). In fact you test again if equals obey the 'reflective' requirement instead of the symmetric requirement.

The notEqualsWorks(Object x, Object y) theory is false: two distinct instances may still be logically equal according to their equals method; you're assuming instances are logically different if they're different references.
Using your own example above, the two distinct datapoints below (a != a2) are nevertheless equal but fail the notEqualsWorks test:
#DataPoint
public static String a = "a";
#DataPoint
public static String a2 = new String("a");

The equalsWorks(Object x, Object y) method is doing the very same test as equalsIsReflexive(Object x). It should be removed.
I also think that notEqualsWorks(Object x, Object y) should be removed since it prevents one to do the other theories with data points that are equal even thought the whole testing is about having such objects.
Without such data points the reflexivity is the only thing that is tested.

Related

Java: Calling super.getClass() from subclass

I know this question has been already asked here, but I fail to understand the "Why" part.
Let us take the following example:
public class First {
First() {
System.out.println(super.getClass());
}
}
public class Second extends First {
Second() {
System.out.println(super.getClass());
}
}
public class Third extends Second {
Third() {
System.out.println(super.getClass());
}
}
When I instantiate an Object of type Third:
public class Main {
public static void main(String[] args) {
Third third = new Third();
}
}
The output is:
class Third
class Third
class Third
And what I expected was (Thinking that super.getClass() should return the name of parent class):
class java.lang.Object
class First
class Second
Which shows that I don't understand how does Inheritance actually work in Java. Kindly help me in getting the right concept in my head.
EDIT
My actual intention was to understand how inheritance actually works (which has been explained very well by Jeff), instead of getting the expected output.
This doubt arose when I was trying to the understand why the following code worked (More specifically, why does super.equals(point3d) worked as it has been passed an object of type Point3D)
public class Main {
public static void main(String[] args) {
Point3D p1 = new Point3D(1, 2, 3);
Point3D p2 = new Point3D(1, 2, 3);
System.out.println(p1.equals(p2)); // Output: true
}
}
public class Point {
private int x;
private int y;
public Point() {
this.x = 0;
this.y = 0;
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object object) {
if (object != null && object.getClass() == this.getClass()) {
Point point = (Point) object;
return point.x == this.x && point.y == this.y;
} else {
return false;
}
}
}
public class Point3D extends Point {
private int z;
public Point3D() {
this.z = 0;
}
public Point3D(int x, int y, int z) {
super(x, y);
this.z = z;
}
#Override
public boolean equals(Object object) {
if (object != null && object.getClass() == this.getClass()) {
Point3D point3D = (Point3D) object;
return super.equals(point3D) && point3D.z == this.z; // Had doubt here
} else {
return false;
}
}
}
It is important to recognize that there is exactly one object here with one reference. It can be tempting to present it as though the superclass is a separate instance of Second residing within your instance of Third, but it is not true; there is no way to refer to that instance because it does not exist.
To be clear: It is not the case that within Third there is a hidden instance of Second to which super refers, and within Second there is a First, and within First there is an Object. Instead, there is a single object that is able to behave as an Object, First, Second, or Third. Regardless of the type of the local variable or reference ("static type"), the instance itself has a "runtime type", which is Third.
The only thing super can do for you is to deliberately invoke a member that belongs to a superclass (JLS 15.11.2) that may be hidden by overriding or naming. This does nothing here, because getClass() is a final method declared on Object. getClass has documentation that it "Returns the runtime class of this Object" (docs). There can be no varying implementation, so you will always receive the type Third as you do in your question.
UPDATE: Unlike getClass, equals is non-final, and can be overridden. Point.equals ensures that the Class returned by getClass is equal, and that x and y are equal. Rather than writing an entirely different implementation of equals, Point3D defers to the Point's definition of equals and additionally checks that the z field is equal, which works because Point checks that object.getClass() == this.getClass(), not that object.getClass() == Point.class. It could not do this simply by calling equals, because that would use the Point3D.equals implementation; instead it has to call super.equals to see how Point would calculate equals.
However, I hope this is an example in a lesson, because polymorphism asserts that a Point3D is-a Point and can do whatever a Point can do (see the Liskov Substitution Principle). For Point and Point3D, this could be misleading: You could write a method double distanceBetween(Point a, Point b) that works as expected using 2D points but gives an incorrect result when using 3D points. In real environments, you'll need to be careful about what your class hierarchies and what they imply.
getClass() is a method on Object. There's not a separate one for each of your subclasses. If you want to go up the chain like that, call getSuperclass() on the result of getClass().

How can I improve this Point class

I'm writing a program that will need to use a limited set of Points to process an image. I figure that I would implement it as an immutable/singleton style class. Before going on to build more of the complex logic surrounding the class I wanted to get an opinion about the core class.
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.HashMap;
public class Point {
private final int x,y;
private final int hashCode;
private static final HashMap<int[],Point> points = new HashMap<>();
private Point(int x,int y){
this.x = x;
this.y = y;
this.hashCode = new HashCodeBuilder().append(x).append(y).toHashCode();
}
public static Point getPoint(int x,int y){
int [] candidate = new int[]{x,y};
if(points.containsKey((candidate))){
return points.get(candidate);
}
Point newPoint = new Point(x,y);
points.put(candidate, newPoint);
return newPoint;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public int hashCode(){
return hashCode;
}
#Override
public boolean equals(Object p){
return this == p;
}
}
I'm going to be using the class to do at least the following functions:
Map different channels in an image by this Point class
Define some static cached custom NavigableSets for ease of traversal
Various Helper functions. In example, get all Points surrounding a Point
Given the information provided, what are some downsides of the provided implementation?
Note: Putting the bulleted list before the code block breaks the display of the code block. Bug?
I think your caching "singletony" stuff may be pointless.
It doesn't save on object creation, as you will always create a candidate[] each time you ask for a Point. And, unless the Point gets reused, you use the memory for candidate and the Map.Entry in your HashMap. So, very roughly speaking, unless each Point gets reused three times, your caching uses more memory. And it always uses a more time.
If you don't cache, change your equals of course.
p.s. the rest seems fine, and immutable is good. You could consider making x and y public final to be more compatible with other Point implementations.
If you are worried about the occupied memory, there is another way to deal with it.
I assuming you have limited dimension for your points, I would suggest to combine your x & y in one variable of long (in case your dimensions is 32 ints long), or even int (if you can fit one dimensions in 16 bit), this way you'll get boost in performance & memory.
Other option is to use int[] array of your coordinates for a point, although that would take more space (since you would have to keep additional pointer reference).
Factory method in your implementation, will work only on single threaded applications, if you have multiple threads creating points, you would need to have some concurrency control in place. This would eat up your resources, because you would effectively need to lock on each point creation.
Another reason, why this Factory method is a bad idea, is that int[] arrays do not override equals and hashCode, you can try to create 2 arrays with same content, to check. So your HashMap would not simply work, and instead of saving memory you would not only create a new Point each time, but also add an entry to your HashMap and perform unnecessary calculations.
So either use Java primitives, or just create a new immutable Point each time if you need too, and go with it, don't overcomplicate with factoryMethods.
You had the right idea of making the Point class immutable but then you went and complicated things with the instance cache. It is not thread safe and it will leak memory because once a Point is created it will forever stay in the hashmap and will never be garbage collected.
Why not keep it simple and make a regular boring value class? Your IDE will even generate it for you.
Then, if you really really really want to have an instance cache, use Guava's Interner class instead of rolling your own. The result will look something like this:
public class Point {
final int x;
final int y;
private Point(int x, int y) {
this.x = x;
this.y = y;
}
static Interner<Point> instanceCache = Interners.newWeakInterner();
public static Point of(int x, int y) {
return instanceCache.intern(new Point(x,y));
}
public int getX() { return x; }
public int getY() { return y; }
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point other = (Point) o;
return this.x == other.x && this.y == other.y;
}
#Override
public int hashCode() { return x * 31 + y; }
}

Constructor overloading same arguments

Suppose I have class with 2 fields: x and y, of type double. Is it possible to define 2 constructors so constructor1 will create object setting its x property to what parameter in constructor tell and y to default and constructor2 vice versa?
public class Test {
private int x;
private int y;
public Test(int x) {
this.x = x;
}
public Test(int y) {
this.y = y;
}
}
I'm trying something like that and I know that it wont work because of overloading rules
No, you can't do that. Typically you'd do something like:
private Test(int x, int y) {
this.x = x;
this.y = y;
}
public static Test fromX(int x) {
return new Test(x, 0);
}
public static Test fromY(int y) {
return new Test(0, y);
}
You might want to consider that pattern (public static factory methods which in turn call private constructors) even when you don't have overloading issues - it makes it clear what the meaning of the value you're passing is meant to be.
No, You cannot have two methods or constructors with the same signature. What you can do is have named static factories.
public class Test {
private int x;
private int y;
private Test(int x, int y) {
this.x = x;
this.y = y;
}
public static Test x(int x) { return new Test(x, 0); }
public static Test y(int y) { return new Test(0, y); }
}
Test x1 = Test.x(1);
Test y2 = Test.y(2);
No, x and y have identical types, so both constructors would have the same type signature and the method resolution is based on parameter type, not name; the compiler has no way of differentiation.
The compiler looks for "Test.Test(int)" regardless of what the name of the parameter is.
The language would need additional feature added, such as named parameters, to do what you want.
If Java ever gets a syntax like C# for property initialization, you'll be able to use that idiom, using a default no-args constructor.
Besides the alternatives of using explicit factory methods, you could pass in a HashMap for your parameters.
public Test(HashMap<string,int> args) {
if(args.containsKey("x"))
x = args.get("x");
if(args.containsKey("y"))
y = args.get("y");
}
But static factory methods are cleaner for most cases. If you need much more, you may need to consider why you need such an idiom in the first place, and revise your class design.

what does the equals() exactly comparing when you using it to compare two objects?

here is the class I want to compare:
public class test
{
private String str=null;
private int integer=0;
private double doubleNum=1.1;
}
now I'm comparing it by instantiate two same classes
public class testEquals
{
public static void main(String[] args)
{
test s1 = new test();
test s2 = new test();
System.out.print(s1.equals(s2));
}
}
the result is
false
Your test class didn't override equals, so it inherits the method from Object:
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
They aren't the same object, so false is returned.
looking at Object.equeals() which is what you are calling, you will see that the default implementation is comparing the object using ==, which is basically comparing the address.
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/lang/Object.java#149

Java - Confused about Comparators and need to use one (I think). More info inside

I created a class called Foo. Foo has three fields, which are all ints: x, y, and z. I want to make a PriorityQueue<Foo> which prioritizes the Foo objects differently in different situations. For instance, I might want to prioritize by x value, or maybe by y value, or maybe by z. But I won't know which value I want to prioritize by until runtime. I've heard you can use comparators to somehow impose an ordering on the fly, which I think would be perfect here.
I'm confused as to exactly how I would do this though. Could someone please show me an example if say I wanted to prioritize on x using a comparator (without having to override the compareTo function in my Foo class)?
Thank you very much.
A comparator is a parameterized interface that allows you to define how two instances of the parameterized type can be compared. let's assume you have the following class
class Foo {
int x;
int y;
int z;
}
Then to define a comparator that orders elements based on their x value then y then z we'd do the following
class XyzComparator implements Comparator<Foo> {
#Override
public int compare(Foo foo1, Foo foo2) {
if(foo1.x != foo2.x) {
return Integer.compare(foo1.x, foo2.x);
}
if(foo1.y != foo2.y) {
return Integer.compare(foo1.y, foo2.y);
}
return Integer.compare(foo1.z, foo2.z);
}
}
Similarly you can define comprators that compare elements based first on their y value then x the z...etc
Finally at runtime you can instantiate a PriorityQueue with that comparator
PriorityQueue<Foo> queue;
if(x_then_y_then_z) {
queue = new PriorityQueue<Foo>(10, new XyzComparator());
} else if (y_then_x_then_z) {
queue = new PriorityQueue<Foo>(10, new ZxyComparator());
}
For more information take a look at the priority queue javadoc as well as the comparator javadoc
Edit: Please see #buritos comment regarding integer overflow.
Comparator<Foo> comparator = new Comparator<Foo>() {
#Override
public int compare(Foo o1, Foo o2) {
if (o1.x > o2.x)
return 1;
else if(o1.x < o2.x)
return -1;
else
return 0;
}
};
PriorityQueue<Foo> queue = new PriorityQueue<Foo>(10, comparator);
...

Categories