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 :)
Related
import java.util.Stack;
public class StackIntro {
public static void main(String[] args){
Stack clapper = new Stack();
for( int i=0; i<11; i++){
clapper.push(i);
}
while(!clapper.isEmpty()){
System.out.print ( clapper.pop() ); //FILO
System.out.print ( ',' );
if(clapper.size()==1){
System.out.print(clapper.pop()); //FILO
System.out.println("...");
}
}
System.out.println("Lift-off.");
clapper.removeAllElements();
}
}
So basically I just wanted to see how numbers go in and out of a stack. The FILO comment shows this. I was told that I should actually change line 8 :
clapper.push(i); //previous
clapper.push(new Integer(i)); //new
I don't understand what this would accomplish, or the difference between the two.
Although due to autoboxing both lines of code result in an Integer object with value 1 being pushed on the stack, the two lines do not have exctly the same effect.
Autoboxing uses the Integer cache, which is required by the JLS for values from -128 to 127, such that the resulting Integer instance is the same instance for any value in that range.
However, invoking the int constructor creates a new Integer instance every time it's called.
Consider:
Integer a = 1; // autoboxing
Integer b = 1; // autoboxing
System.out.println(a == b); // true
Integer c = new Integer(1);
Integer d = new Integer(1);
System.out.println(c == d); // false
This distinction may cause different behaviour in your program if you use == (object identity) when comparing values pushed and popped to/from the stack instead of equals().
This would not accomplish much, very possibly not anything at all.
The idea is that clapper.push(T) accepts an object, but i is not an object, it is a primitive, so the compiler will automatically box it into an Integer object before passing it to clapper.push().
Auto-boxing was not a feature of java from the beginning, so there may still exist some old-timers who are uncomfortable with it. But that should be entirely their own problem. Java has come a long way since then. Auto-boxing is taken for granted, we do not even give it any thought anymore.
Passing i and having the compiler auto-box it is exactly the same as as passing new Integer(i).
What is the difference between the following:
Integer in = (Integer)y;
and
Integer in = new Integer(y);
I want to convert int type to Integer type and vice versa. Here is my code for doing that:
public class CompareToDemo {
public static void main(String[] args) {
// Integer x=5;
int y=25;
System.out.println(y+" this is int variable");
Integer in = (Integer)y;
//Integer in = new Integer(y);
if(in instanceof Integer){
System.out.println(in +" this is Integer variable");
}
}
}
If all you want to do is to convert an int primitive to an Integer object,
you have four options
Integer in = (Integer)y; // 1 explicit cast
Integer in = y; // 2 implicit cast (autoboxing)
Integer in = new Integer(y); // 3 explicit constructor
Integer in = Integer.valueOf(y); // 4 static factory method
The most preferable way here is 2 (autoboxing). The explicit constructor (3) is the less preferable, as it might have some small performance hit.
Also, they are not strictly equivalent. Consider:
public static void main(String[] args) {
int x = 25;
Integer a = new Integer(x);
Integer b = new Integer(x);
System.out.println(a == b); // false
Integer c = Integer.valueOf(x);
Integer d = Integer.valueOf(x);
System.out.println(c == d); // true
Integer e = (Integer)x;
Integer f = (Integer)x;
System.out.println(e == f); // true
}
This is because small integers are cached (details here).
Briefly speaking,
The line Integer in = (Integer)y; uses an unnecessary cast.
The line Integer in = new Integer(y); creates an Integer instance.
Each case in detail
First, let's consider the case with explicit casting.
Integer i = (Integer)10;
The compiler understands that 10 is an int primitive type and the fact that it has to be wrapped by its Integer to make it compiles. It seems javac will make the following:
Integer i = (Integer)Integer.valueOf(10);
But the compiler is smart enough to do unnecessary casting, (Integer) just will be omitted:
Integer i = Integer.valueOf(10);
Next, there is the case with instance creation.
Integer i = new Integer(10);
Here is all simply. A new instance of Integer class will be created anyway. But, as the documentation says, usually, it is not appropriate way:
It is rarely appropriate to use these constructors. The static factories valueOf() are generally a better choice, as it is likely to yield significantly better space and time performance.
Conclusion
In everyday code writing, we usually use autoboxing and unboxing. They are automatic conversions between the primitive types and their corresponding object wrapper classes (has been introduced in Java 5). So you needn't think much about Xxx.valueOf(xxx) and .xxxValue() methods. It is so convenient, isn't it?
Integer i = 10; // autoboxing
int j = i; // unboxing
For every primitive type in java, there is a corresponding wrapper class. You can convert between these primitive type and corresponding wrapper class. This is called boxing and unboxing. When you write
Integer in = (Integer)y; //this is unnecessary casting
or
Integer in = new Integer(y); //create a new instance of Integer class
You're mainly converting between primitive type and wrapper class. But Java has a feature called Auto Boxing and Unboxing Where java will do these casting for you. Just write
int iPrimi = 20;
Integer iWrapper = iPrimi; //Autoboxing
int iPrimi2 = iWrapper; //Auto unboxing
Autoboxing and Unboxing decrease performance. Primitives seems to be 2-3 times faster then it’s Integer equivalent. So do not use them if you don't need to.
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).
I thought the Collections.binarySearch()would return never return a 0 cause the comparison in the comparator is between two Integer which the == operation would always been false, but the run results let me down... Can someone help me out?
public class ObjectCompare {
static Comparator<Integer> com = new Comparator<Integer>(){
public int compare(Integer i, Integer j) {
return i<j?-1:(i==j?0:1);// i thought i==j would never return true
}
};
public static void main(String[] args){
String[] array = {"0","1","2","3","4","5"};
List<Integer> list = new ArrayList<Integer>();
Integer k = new Integer(1);
Integer l = new Integer(1);
System.out.println(k==l); // this return's false
for(String s : array)
list.add(Integer.valueOf(s));
System.out.println(Collections.binarySearch(list,1,com));// this returns 1
}
}
If I understand well, the question is "why does the binarySearch actually find the item in the list, when my comparator compares instances?" Right?
Well, the answer is as simple as that: because actually it compares two identical instances (references). Integer class maintains a pool of cached instances for values between -128 and 127 (inclusive). This pool of instances is always used when valueOf is called with an argument between these values.
Here you have 2 calls to valueOf(1) (more or less explicit) in your code.
One is here: list.add(Integer.valueOf(s));. For one iteration through the loop, the call is actually list.add(Integer.valueOf("1"); Behind the scenes, valueOf(int) is called.
And the second is here: Arrays.binarySearch(array,1,com). The boxing operation from the literal 1 to the Integer instance is actually performed via an invocation of valueOf(int).
System.out.println(k==l);
This would return false as they are different objects. As known, you need to use equals() method to compare the values of two Integer objects.
return i<j?-1:(i==j?0:1);
This is the return statement of the compare() method. i will not be equal to j unless the same object is present in twice in the list. Note that the compare() method is called by the Collections.sort(list, comparator) method internally. This is not called by the binarySearch() method directly.
System.out.println(Collections.binarySearch(list,1,com));
This returns 1, but the 1 here represents the index at which the search item was found. It would return 3 if your search item was System.out.println(Collections.binarySearch(list,3,com));. The 1 returned by binarySearch() is not from the compare() method. The binary search algorithm will internally call the equals() method to compare the Integer values during the search.
Hence, the i == j clause in the compare() which you thought would never satisfy, has nothing to do with the actual binary search which is performed on the list of Integers.
From the docs of Collections.binarySearch(List, searchItem, comparator):
Searches the specified list for the specified object using the binary search algorithm. The list must be sorted into ascending order according to the specified comparator (as by the sort(List, Comparator) method), prior to making this call.
use this
System.out.println(k.equals(l)); // this return's true
instead of
System.out.println(k==l); // this return's false
because == this compare the address of your integer objects not value...
return i<j?-1:((i.equals(j))?0:1);// i thought i==j would return true
instead of
return i<j?-1:((i==j)?0:1);// i thought i==j would never return true
Integer is the boxed variant of int, i.e. a reference type. You need to use the Integer#equals method to test for equality as == will just test if the references are equal:
static Comparator<Integer> com = new Comparator<Integer>(){
public int compare(Integer i, Integer j) {
return i < j ? -1 : (i.equals(j) ? 0 : 1);
}
};
Edit
Now that I think about it, writing a Comparator for Integer is kind of pointless, since Integer already implements Comparable<Integer>.
I've taken the liberty to re-shape the program to focus on the question at hand: the i == j in the compare() method:
import java.util.Arrays;
import java.util.Comparator;
public class StackOverflow {
static Comparator<Integer> com = new Comparator<Integer>(){
#Override
public int compare(Integer i, Integer j) {
int res = 0;
if(i<j){
res = -1;
} else if(i == j ){
res = 0;
} else {
res = 1;
}
return res;
}
};
public static void main(String[] args){
Integer[] array = {0,1,2,3,4,5};
System.out.println(Arrays.binarySearch(array,1,com));
}
}
If you debug/step through the code you do see that when comparing 1 with 1, the code goes into the res = 0. This is likely to be an autoboxing quirck? Maybe as it has to auto-unbox them for i
This question already has answers here:
How can I properly compare two Integers in Java?
(10 answers)
Closed 5 years ago.
I have the following code:
public class Test {
public static void main(String[] args) {
Integer alpha = new Integer(1);
Integer foo = new Integer(1);
if(alpha == foo) {
System.out.println("1. true");
}
if(alpha.equals(foo)) {
System.out.println("2. true");
}
}
}
The output is as follows:
2. true
However changing the type of an Integer object to int will produce a different output, for example:
public class Test {
public static void main(String[] args) {
Integer alpha = new Integer(1);
int foo = 1;
if(alpha == foo) {
System.out.println("1. true");
}
if(alpha.equals(foo)) {
System.out.println("2. true");
}
}
}
The new output:
1. true
2. true
How can this be so? Why doesn't the first example code output 1. true?
For reference types, == checks whether the references are equal, i.e. whether they point to the same object.
For primitive types, == checks whether the values are equal.
java.lang.Integer is a reference type. int is a primitive type.
Edit: If one operand is of primitive type, and the other of a reference type that unboxes to a suitable primitive type, == will compare values, not references.
Integer objects are objects. This sounds logical, but is the answer to the question. Objects are made in Java using the new keyword, and then stored in the memory. When comparing, you compare the memory locations of the objects, not the value/properties of the objects.
Using the .equals() method, you actually compare the values/properties of objects, not their location in memory:
new Integer(1) == new Integer(1) returns false, while new Integer(1).equals(new Integer(1)) returns true.
ints are a primitive type of java. When you create an int, all that is referenced is the value. When you compare any primitive type in Java, all that is compared is the value, not the memory location. That is why 5 == 5 always returns true.
When you compare an Integer object to a primitive type, the object is cast to the primitive type, if possible. With an Integer and an int this is possible, so they are compared. That is why Integer(1).equals(1) returns true.
What you'll use new Integer(1) to create new object, it creates a totally different object each time even though it has the same value. The '==' checks if the objects are same, not data values. In your case, you could have checked the value as follows :
if(alpha.intValue() == foo.intValue()) {
//
}
Integer == int here auto boxing applied ( so Integer converted to int before comparision) so true.. but Integer == Integer here object comparison so as reference are different so false..
First example:
Using the == operator between objects checks for reference equality, and since you are comparing two different objects they do not equal.
Second example:
When using the == between a wrapper type (Integer, Long, etc.) and a numeric type (int, long, etc.) the wrapper type is unboxed and the equality check is done between the two primitive numeric types (I.e. between int and int). The unboxing is part of binary numeric promotion, read more here: http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2