I have a matrix class which takes in a generic object which extends Number.
For example:
public class Matrix<T extends Number>
I am trying to compare two matrices which have the same values:
Matrix:
row=[0] 273 455
row=[1] 243 235
row=[2] 244 205
row=[3] 102 160
and
Matrix:
row=[0] 273 455
row=[1] 243 235
row=[2] 244 205
row=[3] 102 160
In the Matrix class, I have a equals method which looks like this:
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Matrix))
return false;
Matrix<T> m = (Matrix<T>) obj;
if (this.rows != m.rows)
return false;
if (this.cols != m.cols)
return false;
for (int i=0; i<matrix.length; i++) {
T t1 = matrix[i];
T t2 = m.matrix[i];
if (!t1.equals(t2))
return false;
}
return true;
}
This line is failing:
t1.equals(t2)
even when the two numbers are equal. e.g. "273" and "273"
When I debug the equals method, it is failing because it is assuming the numbers are Longs:
This is from Java SDK Long.class:
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
Essentially, it fails because the obj isn't an instance of Long.
I can easily change my equals method to do:
if (t1.longValue()!=t2.longValue())
return false;
But I am wonder what is the correct way to check for equality in this situation and why the equals method on the generic T is assuming it's a Long.
EDIT:
My testing code is defining ''Matrix generic type of Integer'' which makes the equality testing (which is comparing using Long) strange to me.
Testing code:
Matrix<Integer> matrix1 = new Matrix<Integer>(4, 3);
matrix1.set(0, 0, 14);
matrix1.set(0, 1, 9);
matrix1.set(0, 2, 3);
matrix1.set(1, 0, 2);
matrix1.set(1, 1, 11);
matrix1.set(1, 2, 15);
matrix1.set(2, 0, 0);
matrix1.set(2, 1, 12);
matrix1.set(2, 2, 17);
matrix1.set(3, 0, 5);
matrix1.set(3, 1, 2);
matrix1.set(3, 2, 3);
Matrix<Integer> matrix2 = new Matrix<Integer>(3, 2);
matrix2.set(0, 0, 12);
matrix2.set(0, 1, 25);
matrix2.set(1, 0, 9);
matrix2.set(1, 1, 10);
matrix2.set(2, 0, 8);
matrix2.set(2, 1, 5);
Matrix<Integer> result1 = new Matrix<Integer>(4,2);
result1.set(0, 0, 273);
result1.set(0, 1, 455);
result1.set(1, 0, 243);
result1.set(1, 1, 235);
result1.set(2, 0, 244);
result1.set(2, 1, 205);
result1.set(3, 0, 102);
result1.set(3, 1, 160);
Matrix<Integer> matrix3 = matrix1.multiply(matrix2);
if (!matrix3.equals(result1)) {
System.err.println("Matrix multiplication error. matrix3="+matrix3+" result1"+result1);
return false;
}
Here is the link to the Matrix code without the equals() method defined. I haven't checked in the equals() code yet.
The reason that the program is using Long.equals, even though all your test code uses Matrix<Integer>, is simply that you're storing a Long in it. The code has this:
public class Matrix<T extends Number> {
private T[] matrix = null;
and then in the constructor:
this.matrix = (T[]) new Number[rows * cols];
which of course creates an array of null references. But when you create the array using multiply,
Long result = 0l;
for (int i = 0; i < cols; i++) {
Long l = row[i].longValue() * column[i].longValue();
result += l;
}
output.set(r, c, (T) result);
where set looks like
public void set(int row, int col, T value) {
matrix[getIndex(row, col)] = value;
}
The thing is, that even though you tried to put a (T) cast on the result, it doesn't do anything. Note that the language doesn't let you cast between Long and Integer types:
Long x = 3L;
Integer y = 4;
x = (Long)y; // illegal
y = (Integer)x; // illegal
Because of type erasure, the compiler doesn't try to check the cast to (T), but displays an unchecked warning if you don't suppress warnings. (It checks to make sure that the thing you're casting is some Number, but that's all.) It does not generate any code that would do a conversion. Thus, even if the multiply method is called on Matrix<Integer>, the code will not try to convert your Long to an Integer. The cast has no effect, and the result is that a reference to a Long is stored in your matrix array. (This runs OK because the code cannot check to make sure that the type is the same as T, again due to type erasure.) So then later, when you use matrix[i].equals, since a Long is stored in the matrix, Long.equals is called.
Unfortunately, I don't think there's a good way to convert a number to an object of some Number class that isn't known at compile time. You could pass T's class as a parameter to the constructor, and then use reflection to try to find a constructor for that class that takes a long parameter, but that's ugly.
Unfortunately, there is no way to check for value equality of Number implementations.
The closest thing you can generically do is:
public static boolean valueEquals(Number n1, Number n2) {
return n1.longValue() == n2.longValue() && n1.doubleValue() == n2.doubleValue();
}
This method will return sane results for all primitive wrapper types, but not for all instances of BigDecimal, BigInteger and anything else that offers precision beyond the limits of long/double.
The reason both longValue and doubleValue are compared is that if you used only longValue, 1L and 1.1D would be detected as equal (due to truncation in Double.longValue()), while if you used just doubleValue, there would be multiple distinct long values that match a single double (e.g. integer values in the range of 2^53 to 2^63 can be exactly represented as longs, but they do get rounded in the least significant bits when represented as double).
Since you already know that the values are not always instances of Long, you have to compare the numeric values yourself as you already found out.
To answer your question "I wonder [...] why the equals method on the generic T is assuming it's a Long":
Because it is one. When calling t1.equals(t2) with t1 being a Long, the equality check is done by Long.equals(Object). And that results in false if the parameter is not of the same type.
Since you cant be sure which type "arrives" in your equals method, you should implement a Comparator that can handle all the possible types. For instance: How do you compare an Integer to a Double? Both are subclasses of Number.
...why the equals method on the generic T is assuming it's a Long.
The reason is simple: Assuming the matrix you're testing with is of type Matrix<Long>, then t1 is an instance of Long (the generic type just allows you to use Long here and has no relevance at runtime) and thus Long.equals() would be called.
In the following case Integer.equals() should be called:
Matrix<Integer> m1 = ...;
Matrix<Long> m2 = ...;
m1.equals( m2 );
Since members of m1 are of type Integer, the call t1.equals(t2) would have the signature Integer.equals(Long).
So what could you do to be able to get two matrices of different types but with equal values to be equal?
The general problem would be that you should use compareTo() to check for value equality (since in some cases like BigDecimal mathematically equal values like 2.0 and 2.00 would not result in equals() returing true.
Unfortunately using T extends Number & Comparable<T> would not be an option (see the comments for reference, as well as here: Why doesn't java.lang.Number implement Comparable?), because you would not be able to call Long.compareTo(Integer) that way.
Thus you'd either have to fall back to primitive values and distinguish between integer and floating point values (thus calling t1.longValue() or t1.doubleValue()) or use a Comparator<Number> whose implementation of compareTo(Number lhs, Number rhs) would handle that. (There should be ready to use Comparators like this: http://www.jidesoft.com/javadoc/com/jidesoft/comparator/NumberComparator.html).
If you want to support larger numbers like BigInteger and BigDecimal you could also consider using BigDecimal and create an instance for every value. This should result in some flexibility but would also incur some performance cost. (Disclaimer: this is just an untested idea so don't just take it as is, it is just meant to provide some input for your own thought process).
Related
Why can't Byte and Number/Integer be compared? I have attached my source code. See the comments. Also why I have to cast 88 into byte, isn't it done automatically with auto-boxing and auto-unboxing?
package com.practice;
public class Generics<T extends Number>
{
T ob;
public Generics(T i)
{
ob = i;
}
T getObj()
{
return ob;
}
boolean compare(Generics<?> o)
{
if (this.ob == o.ob)
{
return true;
}
else
{
return false;
}
}
public static void main(String[] args)
{
Generics<Number> num = new Generics<>(88);
// Generics<Byte> Byte = new Generics<>(88); //why this does not
// compile?
Generics<Byte> Byte = new Generics<>((byte) 88);
Generics<Integer> integer = new Generics<>(88);
System.out.println(num.compare(integer)); // this is true!!
System.out.println(num.compare(Byte)); // why False?
System.out.println(integer.compare(Byte)); // Why false?
}
}
Why I have to cast 88 into byte, isn't it done automatically with auto-boxing and auto-unboxing?
By default, a numeric literal (like 88) is an int. The auto-boxing does happen but the compiler boxes it into an Integer and not a Byte because, as I just told, it's an int.
Generics<Number> num = new Generics<>(88);
Generics<Integer> integer = new Generics<>(88);
Since, an Integer IS-A Number both of the above work just fine.
Generics<Byte> Byte = new Generics<>(88); // why this does not compile?
Now, in case of Generics<Byte>, the constructor becomes Generics(Byte i), which fails because an Integer cannot be assigned to a Byte as there's no inheritance between them. They both extend Number and are sibling classes.
Generics<Byte> Byte = new Generics<>((byte) 88);
So, to pass in a Byte and satisfy the compiler, the (byte) cast is required. Now the auto-boxing happens again but from a byte to Byte this time.
Regarding equality, your compare() method implementation is flawed because it only compares references this.ob == o.ob and not their values.
System.out.println(num.compare(integer)); // this is true!!
System.out.println(num.compare(Byte)); // why False?
System.out.println(integer.compare(Byte)); // Why false?
This however worked for integer comparison num.compare(integer) because you chose a small value 88 which falls in the range of values (-128 to +127) cached and shared by the JVM among auto-boxed Integer instances. If you run your program again with a larger value like 888, it will print false for the same comparison.
So, to fix your compare() method, you'll need to sort of unbox their numeric values.
return (this.ob.floatValue() == o.ob.floatValue());
PS: The equals() method wouldn't help here. Check the source code to know why :)
I read that the rule for the return value of these methods is that for obj1.compareTo(obj2) for example, if obj2 is under obj1 in the hierarchy, the return value is negative and if it's on top of obj1, then it's positive (and if it's equal then it's 0). However, in my class I saw examples where Math.signum was used in order to get -1 (for negative) and 1 (for positive) in the compareTo method.
Is there any reason for that?
EDIT:
Here is the code I meant:
Comparator comp = new Comparator() {
public int compare(Object obj1, Object obj2) {
Book book1 = (Book) obj1;
Book book2 = (Book) obj2;
int order = book1.getAuthor().compareTo(book2.getAuthor());
if (order == 0) {
order = (int) Math.signum(book1.getPrice() - book2.getPrice());
}
return order;
};
Is there any reason for using Math.signum
Yes there is.
order = (int) Math.signum(book1.getPrice() - book2.getPrice());
Suppose you have replace the above line with this
order = (int)(book1.getPrice() - book2.getPrice());
Now let us assume
book1.getPrice() returns 10.50
book2.getPrice() returns 10.40
If you do not use signum you will never have any compile time or run time error but value of order will be 0. This implies that book1 is equals to book2 which is logically false.
But if you use signum value of order will be 1 which implies book1 > book2.
But it must be mentioned that you should never make any assumption about compare function returning value between 1 and -1.
You can read official document for comparator http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html.
Any negative number will do to show that a < b. And any positive number will show that a > b. -1 and 1 serve that purpose just fine. There's no sense of being "more less than" or "more greater than"; they are binary attributes. The reason that any negative (or positive) value is permitted is probably historical; for integers it's common to implement the comparator by simple subtraction.
No.
PS: Frequent error in implementation is to use subtraction
public int compareTo(Object o) {
OurClass other = (OurClass)o; //Skip type check
return this.intField - other.intField;
}
It is wrong because if you call new OurClass(Integer.MIN_VALUE).compareTo(new OurClass(Integer.MAX_VALUE)) you get overflow. Probably Math.abs is attempt (failed) to deal with this problem.
The only reason I can see is that if you want to compare two ints for example (a and b), and you write
return a - b;
it might overflow. If you convert them to doubles and use (int)Math.signum( (double)a - (double)b ), you will definitely avoid that. But there are simpler ways of achieving the same effect, Integer.compare( a, b) for example.
If enum implements Comparable so why can't compare with < or >?
public class Dream
{
public static void main(String... args)
{
System.out.println(PinSize.BIG == PinSize.BIGGER); //false
System.out.println(PinSize.BIG == PinSize.BIG); //true
System.out.println(PinSize.BIG.equals(PinSize.BIGGER));//false
System.out.println(PinSize.BIG > PinSize.BIGGERER);// compilation error
//can't be compared
System.out.println(PinSize.BIG.toString().equals(PinSize.BIGGER));// #4
PinSize b = PinSize.BIG ;
System.out.println( b instanceof Comparable);// true
}
}
enum PinSize { BIG, BIGGER, BIGGERER };
You can do this:
PinSize.BIGGEST.ordinal() > PinSize.BIG.ordinal() // evaluates to `true`
Of course, assuming that BIGGEST was declared after BIG in the enumeration. The ordinal value in an enumeration is implicitly tied to the declaration order, by default the first value is assigned value 0, the second value 1 and so on.
So if yo declared the enumeration like this, things will work:
public enum PinSize {
SMALLEST, // ordinal value: 0
SMALL, // ordinal value: 1
NORMAL, // ordinal value: 2
BIG, // ordinal value: 3
BIGGER, // ordinal value: 4
BIGGEST; // ordinal value: 5
}
Implementing Comparable doesn't mean that you can use < or >. You can only use those with numeric values.
Implementing Comparable means that there's a compareTo() method. Try this:
System.out.println(PinSize.BIG.compareTo(PinSize.BIGGER));
The compareTo() method will return an int that is smaller than, equal to, or bigger than 0, depending on which value is "bigger". In the case of enum values, the "size" depends on the order of the enum value definitions.
The answers provided explain the problem well, but I would like to add my insights, because I feel that they don't answer question "why can't compare with < or >"?. The problem comes down to comparing references. PinSize.BIGGEST and PinSize.BIGGERER are reference variables. The same as the below:
String s;
int[] array;
MyObject myObject;
They represent addresses in memory. What is more, enums are singletons so there is always one object of the specified kind. Because of that the below line is allowed and returns true.
System.out.println(PinSize.BIG == PinSize.BIG); //true
Trying to check if one address in memory is greater or smaller than the other address in memory is impossible. Implementing Comparable interface and compareTo() method gives a chance to provide your own custom way of comparing objects not addresses in memory.
System.out.println(PinSize.BIG > PinSize.BIGGERER); // not possible
Consider two references of type Integer that call the static factory method valueOf as shown below:-
Integer a = Integer.valueOf("10");
Integer b = Integer.valueOf("10");
Considering that Integer is immutable, is it ok to compare a and b using == instead of using equals method. I am guessing that the valueOf method makes sure that only one instance of Integer with the value 10 is created and a reference to this instance is returned for every Integer created with a value 10.
In general, is it ok to compare two references of an immutable class that are created using a call to the same static factory method by using == instead of equals?
Edit:
The Integer class was used just as an example. I am aware thar Intgers upto 127 will return true if they are compared using ==. What i need to know is that when l create my own immutable class, say MyImmutable with a method create() that will ensure that no duplicate MyImmutable objects are created, will it be ok if I compare 2 MyImmutable references created using the create method by using == instead of equals.
No, that's not safe in general. The == operator compares the references, not the values.
Using == happens to work for integers between -128 and 127, but not for other integers. The following code demonstrates that == won't always work:
Integer a = Integer.valueOf(10);
Integer b = Integer.valueOf(10);
System.out.println(a == b);
true
Integer c = Integer.valueOf(1000);
Integer d = Integer.valueOf(1000);
System.out.println(c == d);
false
See it working online: ideone
The explanation for this behaviour lies in the implementation of Integer.valueOf:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
source
Not also that the standard requires that boxing integers for small inputs (-128 to 127) gives objects with equal references.
5.1.7 Boxing Conversion
If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
However the standard makes no such guarantees for integers outside this range.
In general, is it ok to compare two references of an immutable class that are created using a call to the same static factory method by using == instead of equals?
As shown above, it won't work in general. But if you ensure that two immutable objects with the same value always have the same reference, then yes, it could work. However there are some rules you must follow carefully:
The constructor must not be public.
Every object you create via the static method must be cached.
Every time you are asked to create an object you must first check the cache to see if you have already created an object with the same value.
== and equals() is fundamentally different.
You should read this post for more details:
Difference between Equals/equals and == operator?
It has nothing to do with immutable objects.
If your factory method returns the same object for equal inputs, it's safe to compare them with ==. For example String.intern works this way. Enums are also could be compared with ==. But Integer.valueOf returns the same object only for -128 ... 127 range (in default configuration).
Integer.valueOf(127) == Integer.valueOf(127)
but
Integer.valueOf(128) != Integer.valueOf(128)
Generally speaking you should use equals method to compare any objects. Operator == could be used to improve performance, when there are small number of different values for object. I wouldn't recommend to use this method, unless you are 100% sure in what you are doing.
Immutability and equality do not necessarily have something to do with each other. == compares for reference equality, that means, it compares if both variables point to the very same instance of the object. Equality means that both objects share the same value. Immutability now means that you can not alter an object after its construction.
So, you might have two immutable obejcts, that represents the same value (meaning, they are equals so that a.equals(b) returns true) but that are not the same instance.
I have a little example for you here:
public class MyPoint {
private int x;
private int y;
public MyPoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof MyPoint))
return false;
MyPoint p = (MyPoint) obj;
return this.x == p.x && this.y == p.y;
}
/**
* #param args
*/
public static void main(String[] args) {
MyPoint p = new MyPoint(2, 2);
MyPoint q = new MyPoint(2, 2);
MyPoint r = q;
System.out.println(p == q);
System.out.println(p == r);
System.out.println(q == r);
System.out.println(p.equals(q));
System.out.println(p.equals(r));
System.out.println(q.equals(r));
}
}
The output is:
false
false
true
true
true
true
MyPoint is immutable. You can not change its values / its state after is has been initialized. But, as you can see, two objects of myPoint might be equal, but they might not be the same instance.
I think what you have in mind is some kind of flyweight pattern, where only one object exists for every possible state of the object. Flyweight also means commonly that those obejcts are immutable.
They are not the same object, so == will not be true. With objects, be safe and use equals().
In Java, all numeric types extend from java.lang.Number. Would it be a good idea to have a method like the following:
public boolean areEqual(Number first, Number second) {
if (first != null && second != null) {
return first.equals(second);
}
}
I'm concerned about cases where a double 2.00000 does not equal an int 2. Are these handled by the built-in equals? If not, is there any way to write a simple number compare function in java? (external libraries such as apache commons are ok)
A Double is NEVER equals to an Integer. Moreover, a double is not the same as a Double.
Java has primitive types and reference types. The truly numeric types in Java do not extend from Number, because they're primitives.
You may want to consider a system where you're not mixing types, because that usually will cause a lot of trouble with implicit/explicit conversions that may/may not lose information, etc.
Related questions
On int vs Integer:
What is the difference between an int and an Integer in Java/C#?
Is Java fully object-oriented?
On Number comparison:
Why doesn't java.lang.Number implement Comparable?
Comparing the values of two generic Numbers
See also
Java Language Guide/Autoboxing
JLS 4.2 4.2 Primitive Types and Values
The numeric types are the integral types and the floating-point types.
The integral types are byte, short, int, and long and char.
The floating-point types are float and double.
On mixed-type computation
Mixed-type computation is the subject of at least 4 puzzles in Java Puzzlers.
Here are various excerpts:
it is generally best to avoid mixed-type computations [...] because they are inherently confusing [...] Nowhere is this more apparent than in conditional expressions. Mixed-type comparisons are always confusing because the system is forced to promote one operand to match the type of the other. The conversion is invisible and may not yield the results that you expect
Prescription: Avoid computations that mix integral and floating-point types. Prefer integral arithmetic to floating-point.
To compare two Numbers in Java you can use the compareTo from BigDecimal. BigDecimal can hold everything from short until double or BigInteger, so it's the perfect class for this.
So you can try to write something like this:
public int compareTo(Number n1, Number n2) {
// ignoring null handling
BigDecimal b1 = BigDecimal.valueOf(n1.doubleValue());
BigDecimal b2 = BigDecimal.valueOf(n2.doubleValue());
return b1.compareTo(b2);
}
This is surely not the best approach regarding to performance.
The following tests worked so far, at least with JDK7:
assertTrue(compareTo(new Integer(1), new Integer(2)) == -1);
assertTrue(compareTo(new Integer(1), new Double(2.0)) == -1);
assertTrue(compareTo(new Integer(1), new Double(Double.MAX_VALUE)) == -1);
assertTrue(compareTo(new Integer(1), new Double(Double.MIN_VALUE)) == 1);
assertTrue(compareTo(new Integer(1), new Double(1.000001)) == -1);
assertTrue(compareTo(new Integer(1), new Double(1.000)) == 0);
assertTrue(compareTo(new Integer(1), new Double(0.25*4)) == 0);
assertTrue(compareTo(new Integer(1), new AtomicLong(1)) == 0);
The specific method you suggest would fail, because it's using equals() inherited from Object. That is, it would check to see if the Number objects were the same, not whether their values were the same.
If that was just an illustrative example, I will update my answer.
polygene's answer actually pretty much covers the ground I was heading for. You may also be interested in this question: Why doesn't java.lang.Number implement Comparable?.
If you want to know whether the object references are the same, then the existing methods fit the bill. A Double representing 2.0 and an Integer representing 2 are definitely different objects, and certainly not interchangeable in a general sense.
If you just want to know whether the numeric values are the same, you can use the Number.doubleValue() method to convert both numbers to doubles, then compare those numbers together (probably allowing for a small tolerance, as most numbers are represented inexactly, such as 1.99999999996583 for what should be 2, depending on the intermediate calculation steps). Something like the following:
private static final double EPSILON = 0.000000000000001d;
public static boolean areEquivalentNumbers(Number a, Number b)
{
if (a == null)
{
return b == null;
}
else if (b == null)
{
return false;
}
else
{
return Math.abs(a.doubleValue() - b.doubleValue()) < EPSILON;
}
}
On a tangent to a couple of the responses, may I suggest that instead of writing something like:
boolean compare(Object o1, Object o2)
{
if (o1==null)
return o2==null;
if (o2==null)
return false;
return o1.equals(o2);
}
It's much more concise, and I believe slightly more efficient, to write:
boolean compare(Object o1, Object o2)
{
return o1==o2 || o1!=null && o2!=null && o1.equals(o2);
}
If both are null, o1==o2 will return true. If they're not but they're the same object, that's fine too.
Technically the o2!=null is not necessary for most implementations of equals, but if you were really being so generic as to do this on Objects as in the above example, you of course wouldn't know how every override was written.
public static boolean compareTo(Number d1, Number d2) {
Double num1=d1.doubleValue();
Double num2=d2.doubleValue();
if(Double.compare(num1, num2)==0)
return true;
else
return false;
}
OR
public static boolean compareTo(Number d1, Number d2) {
if(d1.doubleValue()==d2.doubleValue())
return true;
else
return false;
}
Comparing numbers between integer and floating point is almost never going to yield what you are after. If however this is a simple exercise, you could implement the comparison by comparing the string representations of the values, as in:
public boolean areEqual(Number first, Number second) {
if (first == null) {
return second == null;
}
if (second == null) {
return false;
}
return first.toString().equals(second.toString());
}
you cannot call
number.equals(number2);
because, if number is a Double and number2 is an Integer, they will not be of the same class and you will get an exception telling you of that fact.
You could write a comparison class yourself that accepts Number objects, but you will have to take into account the different subclasses of Number