Comparing two instances of a class in Java - java

I have a class with two integer members. These members are block and offset numbers. I need to compare two instances of this class with great or less signs. For example;
instance1 < instance2
statement needs to return true if
instance1.blockNumber < instance2.blockNumber;
or
instance1.blockNumber = instance2.blockNumber;
instance1.offset < instance2.offset;
As far as I know Java doesn't support operator overloading. How can I do this such comparison?

Have the class implement the Comparable interface, which gives the compareTo method. You can then use the value of the number (-1 for less, 1 for more, 0 for equals) in your if statements.
If you want to put these objects in lists (say, for sorting) you should also #Override the .equals method.
import java.util.Comparable;
public class BlockOffset implements Comparable<BlockOffset>
{
private int blockNumber;
private int offset;
#Override
public int compareTo(BlockOffset instance2) {
if (this.blockNumber < instance2.blockNumber) return -1;
if (this.blockNumber > instance2.blockNumber) return 1;
if (this.offset < instance2.offset) return -1;
if (this.offset > instance2.offset) return 1;
return 0;
}
}

If the class type is your own code than you can have it implement Comparable and define the compareTo method where you can write the logic. Then, you can compare them using compareTo.

you can implement and use comparable or comparator

Related

how do I check if each value of an array is between a range if the array is a non primitive type

Basically, I want to check each value of dice.
If the value is ranges between 1 and 6, inclusive, then I want to such value into the array count.
The problem is that dice is an object, not a primitive, which I declared earlier thus the >= operator does not work.
public int[] getValueCount() {
int[] count;
for (int i = 0; i < dice.length; ++i) {
if ((dice[i] >= 0) && (dice[i] <= 6)) {
count[i] = dice[i];
}
}
return count;
}
I regret to inform you that Java doesn't support operator overloading like other languages such as C++. It was a decision made by the designers with the hope that would make the language simpler to use.
However, there are other options available that you could implement.
The one option that could work very well for you, could be implementing the the Comparable interface.
import java.lang.Comparable;
public class Dice implements Comparable<Dice> {
/* Code */
#Override
public int compareTo(Dice otherDice) {
return this.value - otherDice.value;
}
}
https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html
The good thing is that you can apply many things with it such as using the Comparator interface:
Comparator<Dice> compareByValue = Comparator.comparing(Dice::getValue);
I hope this helps you out.
Implement your own comparison method inside Dice class '.greaterOrEqual(x)' or access the data on Dice class directly and compare that value instead

How to implement compareTo for any types of comparable objects

I don’t know how I can compare 2 comparable objects without some other variable which tells me which is larger. The question is: Create a class called Max that provides a single class method called max. max takes two arguments to objects that can be compared—that is, that implement the Java Comparable interface as shown above. It returns a reference to whichever is larger. If the two objects are equal, you should return the first. How Comparable is implemented is up to each class, and your method will be called on multiple different kinds of objects.
It gives the int compareTo (Object other) method in the interface but I’m having trouble finding a solution.
public class Max implements Comparable
{
public int compareTo(Object other)
{
}
public static Comparable max(Comparable first, Comparable second)
{
int fi = first.compareTo(second);
if(fi >0)
return first;
else if (fi<0)
return second;
return first;
}
}
java.lang.AssertionError: Class should not implement Comparable: expected [false] but found [true]
That is one of the errors. But also I need help writing the compareTo method.
I deleted my previous answer because I think, imho, you are over complicating this. Since the two arguments to max have implemented the Comparable<T> interface, all you have to do is call it as:
int ret = first.compareTo(second);
Then return first or second like you are doing based on the value of ret. That way you don't need to know anything about how it was implemented. Perhaps you could get some clarification from either your instructor or someone else who is working on this (I presume it is for an assignment).
It would be worthwhile for you to create some test classes which implement the interface. You can just make up some variable that represents size.
The keyword for your question is generics. You might want to do some research and read something about it. Take a look at the following example. I've implemented the class Max as a static class to keep it simple:
import java.time.LocalDate;
public class MyTestClass{
public static void main(String args[]) {
Integer i = 16;
Integer j = 15;
Integer m = Max.max(i, j);
System.out.println(m);
String k = "aaaa";
String n = "zzzz";
String s = Max.max(k, n);
System.out.println(s);
LocalDate d = LocalDate.now();
LocalDate e = LocalDate.now().plusDays(2);
LocalDate f = Max.max(d , e);
System.out.println(f);
}
static class Max{
public static <T extends Comparable> T max(T first, T second) {
if (first.compareTo(second) >= 0)
return first;
else
return second;
}
}
}
As you can see, there is a class Max with a single method max which accepts two objects, for example two integers, two strings or two date objects.
Since all these classes implement the comparable interface, you can use the max method for all object types. The compiler then decides during the runtime which comapreTo method to call, that is the compareTo of the class Integer, String, LocalDate or whatever.

The operator > is undefined for the argument type(s) java.lang.Object, java.lang.Object

public void sort(){
//TO DO
int k = start;
int temp = 0;
for(int i=0; i<size-1; i++){
for(int j=0; j<size-1; j++){
if((cir[(k % cir.length)]) > cir[((k+1) % cir.length)]){
temp = cir[(k % cir.length)];
cir[k%cir.length] = cir[(k+1)%cir.length];
cir[(k+1)%cir.length] = temp;
}
k = (k+1)%cir.length;
}
}
}
//Here the cir[] type is object. but why this problem is occurring?
The operators <,> are not defined for Object.
How would you compare them?
Define a method for the class of the object you are using. Say greaterThan(YourObjectType otherobject). Then implement it according to how you want to compare. That depends on YourObjectType.
Edit.
Implement the Comparable interface as added in a comment.
The others have already mentioned it but I will reiterate: if you want to write some generic sort method you'd want to either provide a Comparator or have the elements implement Comparable.
With generics your methods could look like this:
public <T extends Comparable<T>> void sort(T[] array) { ... }
public <T> void sort(T[] array, Comparator<T> comparator) { ... }
Both variants require the user to provide some code that defines how <, == and > are defined for the objects in question (the methods Comparable.compareTo(right) or Comparator.compare(left, right) return a negative (normally -1) int, 0 or a positive int (normally 1) to indicate <, == or >).
In general, you'd use Comparable if you can define a natural (default) ordering, e.g. if you'd work with an array of people they normally might be ordered by name.
Comparator on the other hand is more flexible and normally used if you can't or don't want to use a default order. In that case you'd provide a comparator for each case, e.g. when you'd want to sort cars either by price or speed you'd provide a comparator that internally either compares prices or speed.
Note that this doesn't work for primitives like int etc. Thus you'd either have to convert them to their wrapper classes, e.g. Integer or provide custom methods that make use of the "normal" operators.

How to define a generic comparable array class?

I want to define a generic class ComparableList<> that extend ArrayList and implements Comparable interfaces, such that two objects of type ComparableList can be compared using the compareTo method. The compareTo should perform a lexicographic comparison.
Here's my code:
class ComparableList <T extends Comparable<T>> extends ArrayList implements Comparable<ComparableList>{
#Override
public int compareTo(ComparableList o){
Iterator citer = this.iterator();
Iterator oiter = o.iterator();
while (citer.hasNext() && oiter.hasNext()){
if (citer.next() > oiter.next()){
return 1;
}else if (citer.next() < oiter.next()){
return -1;
}else {
if (!citer.hasNext()){
return -1;
}
if(!oiter.hasNext()){
return 1;
}
}
}
return 0;
}
}
and I got error messages like this:
TCL.java:11: error: bad operand types for binary operator '>'
if (citer.next() > oiter.next()){
^
first type: Object
second type: Object
TCL.java:13: error: bad operand types for binary operator '<'
}else if (citer.next() < oiter.next()){
^
first type: Object
second type: Object
I thought it should be a ComparableList but not an Object. Can anyone tell me the reason?
You need to compare the objects using Comparable.comapreTo() (that's why you have <T extends Comparable<T> there). You need to first check for nulls on either side.
Also, each call to Iterator.next() iterates to next element, you don't want to call it twice in one loop iteration - store the items at the loop start then use the stored values.
Comparable doesn't override the > and < operators (nothing can). Since your T implements Comparable, use compareTo:
int result = citer.next().compareTo(oiter.next());
if (result != 0) {
return result;
} else {
if (citer.hasNext()) {
return -1;
}
if (oiter.hasNext()) {
return 1;
}
}
Note that that also calls next only once per iteration, since next advanced the iterator.
Each element in your ComparableList is of type T extends Comparable<T>, for sure the binary operator is not available for it (Java doesn't have operator overloading), but since it extends Comparable, you have compareTo to be used as replacement for < and >. Use it instead.

Is there any Comparable not comparable to itself?

In the contract of Comparable, there's nothing forcing an object to be comparable to itself. It's just
strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
which implies that it's recommended for x.compareTo(x) not to throw. But it's possible to write a
class X implements Comparable<Y> {
...
}
where X and Y are two unrelated classes. I can't see what it could be good for, but in the Java 8 version of HashMap there's even a corresponding check.
Is it allowed to implement X implements Comparable<Y> with two unrelated classes?
Does it make any sense?
I guess the answers are yes and no, but it's just a guess
Comparable promotes a contract where comparisons should be consistent with equals, i.e. (a.compareTo(b) == 0) == a.equals(b). But it does not force you to do so and any weird contract can be enforced.
So you could create a:
class DumbInteger implements Comparable<DumbInteger> {
private final int i;
public DumbInteger(int i) { this.i = i; }
public int compareTo(DumbInteger di) { return 0; }
public boolean equals(Object other) { /* checks */ return other.i == this.i; }
}
And you could also create a:
class DumberInteger implements Comparable<String> {
private final int i;
public DumberInteger(int i) { this.i = i; }
public int compareTo(String s) { return 0; }
public boolean equals(Object other) { /* checks */ return other.i == this.i; }
public static void main(String[] args) {
System.out.println(new DumberInteger(0).compareTo("abc"));
}
}
but there is probably no point in doing that. In any case this is not specific to Java 8 as the Comparable interface has been there since Java 2 and "generified" in Java 5.
But it is probably not a flaw in the Comparable interface per se, because I don't think there is a way in Java to create a generic interface I<T> that can only be implemented by classes that are subtypes of T.
I see I missed one part of the contract and also failed to see the reason why HashMap.comparableClassFor exists.
The contract says
(x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0
so whenever there's an X greater than a Y and a Y greater than an X, then the two instances of X must be comparable to each other. This doesn't leave much freedom:
Either one of the types is empty. This makes no sense at all.
Or all instances of X are smaller or equal to all instances of Y (or the other way round). This is slightly less nonsensical.
So, I'm concluding that it's possible, but makes no sense. The simplest example is
class X implements Comparable<Void> {
public int compareTo(Void v) {
return 43; // or throw or whatever, it doesn't matter
}
}
I guess that the reason for HashMap.comparableClassFor is to support different implementations of a common superclass like
abstract class AByteArray implements Comparable<AByteArray> {}
class SparseByteArray extends AByteArray {...}
class DenseByteArray extends AByteArray {...}
This seems to make sense and can be even consistent with equals.
Does it make any sense?
One issue of having two classes Comparable with each other, is because it tightly couples these classes together. This makes it difficult to re-use the class in another scenario.
Just tried it, it is possible to compare two objects with different classes.
Here is the full code.
https://gist.github.com/cevaris/11099129
X x = new X();
x.xTest = 10;
Y y = new Y();
y.yTest = 100;
System.out.println("x.compareTo(y) == -1: " + (x.compareTo(y) == -1)); //True
System.out.println("y.compareTo(x) == 1: " + (y.compareTo(x) == 1)); //True
Here is the Y implementation.
class Y implements Comparable<X> {
int yTest;
#Override
public int compareTo(X o) {
if(this.yTest < o.xTest) return -1;
if(this.yTest > o.xTest) return 1;
return 0;
}
}
Here is the X implementation.
class X implements Comparable<Y> {
int xTest;
#Override
public int compareTo(Y o) {
if(this.xTest < o.yTest) return -1;
if(this.xTest > o.yTest) return 1;
return 0;
}
}
Well, it can technically be done (as per #cevaris' answer) and can be understood when you have several ways of representing the same object, e.g. an object and its String representation. But it would only make sense if you could implement the same interface twice like:
public class CompInt implements Comparable<CompInt>, Comparable<String> {
but that is forbidden in Java because of type erasure.

Categories