public class SortedLL<T extends Comparable<T>> implements SortedListInterface<T> {
public void add(T data) {
int i;
for(i=0; i<size;i++){
if(data < getAt(i))
break;
}
}
}
I'm here to ask you a question because I don't understand this error.
The data type is generic T and the value obtained by getAt(i) is also T.
And when defining theSortedLL class, I declared it <T extents Comparable <T>>.
Does anyone know why there is an error when comparing these two values and if there is a solution?
THere is no operator overloading in Java. The < operator is only implemented for numeric primitives, not for objects.
Using the Comparable interface, you can call the compareTo method to get that behavior:
if (data.compareTo(getAt(i)) < 0)
Related
I'm trying to make a function that processes sorted lists of (comparable) elements. I'm therefore using the generic <T extends List<? extends Comparable>>, which works will as long as I don't need any list-specific operations that require <? extends Comparable> as input. But in the code snippet below (simplest example: computing the intersection of two sorted lists) the line C.add((Comparable)(A.get(posA))); is rejected by the compiler, claiming that add needs argument ? extends Comparable, which Comparable apparently is not.
public static <T extends List<? extends Comparable>> T intersect (T A, T B) {
T C = (T) A.getClass().newInstance();
int posA = 0;
int posB = 0;
while(posA<A.size()&&posB<B.size()) {
if (A.get(posA).compareTo(B.get(posB))>0) posB++;
else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
else if (A.get(posA).equals(B.get(posB))) {
C.add((Comparable)(A.get(posA)));
posA++; posB++;
}
}
return C;
}
How should I tell the compiler that A.get(posA) is of valid type ? extends Comparable? Apparently casting doesn't work, and I would like the routine to accept and return lists of arbitrary comparables (Integer, String, custom objects, etc.)
Don't you notice all the unsafe type statements in your code, which multiple unsafe casts ?
You have really many of them. It often means that the overall approach is not the correct one.
In fact things are not so complicated if you learn how generics work in Java.
That could help you :
https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
Here are the main things that you should consider according to your actual code :
1) Don't use raw type such as List<? extends Comparable>>. Comparable is a generic class.
2) You cannot add anything but null in a List declared List<? extends Foo>, that is using a upper bounded wildcard. The last one allows to make the List covariant : accepting Foo and any subclass but with the previous limitation. So you don't want to use that.
3) You can instantiate a generic ArrayList without the need to declare the generic method type T for the ArrayList. Using T for the Comparable type will do things really simpler.
4) You want to avoid reflection as much as possible.
By following these ideas you could write a code that could look like :
public static <T extends Comparable<T>> List<T> intersect (List<T> A, List<T> B) {
List<T> list = new ArrayList<>();
int posA = 0;
int posB = 0;
while(posA<A.size()&&posB<B.size()) {
if (A.get(posA).compareTo(B.get(posB))>0) posB++;
else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
else if (A.get(posA).equals(B.get(posB))) {
list.add(A.get(posA));
posA++; posB++;
}
}
return list;
}
That was my original approach, but the problem here is that not every
that the intersection of two non-ArrayList Lists will be an ArrayList
here.
The type of the List will not be known at compile time if you declare List for the parameter. So you will unavoidably finish with unsafe casts.
For example :
#SuppressWarnings("unchecked")
public static <T extends Comparable<T>, L extends List<T>> L intersect(L A, L B) {
if (A.getClass() != B.getClass()) {
throw new IllegalArgumentException("not same type between ...");
}
List<T> list = A.getClass()
.newInstance(); // uncheck
int posA = 0;
int posB = 0;
while (posA < A.size() && posB < B.size()) {
if (A.get(posA)
.compareTo(B.get(posB)) > 0)
posB++;
else if (A.get(posA)
.compareTo(B.get(posB)) < 0)
posA++;
else if (A.get(posA)
.equals(B.get(posB))) {
list.add(A.get(posA));
posA++;
posB++;
}
}
return (L) list; // uncheck
}
This is a typical generics problem.
You are saying that you accept every list of Objects that extend Comparable.
Therefore, it would be perfectly fine of another method would pass a List to your method.
Of course, you shouldn't be allowed to add a Number to that List in your code, even though it would extend Comparable!
You could fix this problem on your code by adding another generic parameter to your method Signature instead of "?". Then you could cast to that parameter in your code.
I try to write a generic class which compares two object with the same type. The class shall get me the smallest of both. My code doesn't work.
public class compare < T > {
private T type1;
private T type2;
public compare(T type1, T type2) {
this.type1 = type1;
this.type2 = type2;
}
public T getSmallest() {
if (type1 > type2) {
return type2;
} else if (type1 == type2) {
return 0;
} else {
return type1;
}
}
}
The primary issue with your code is that the comparison operators < and > are defined ONLY for primitive arithmetic types (char, byte, short, int, long, float and double). You cannot apply those operators to arbitrary reference (non-primitive) types, and generic type parameters MUST be reference types.
It appears you are trying to re-invent the Comparator and Comparable interfaces. Reference types can be "compared" for ordering (i.e. larger/smaller) only if they implement the Comparable<T> interface and provide a compareTo() method, or using a helper class that implements Comparator<T>. In the first case (implements Comparable<T>) the class itself defines the comparison in whatever terms are appropriate based on its internal state; in the second case the comparison is specified in the helper implements Comparator<T> class, based on whatever internal state is visible to the helper.
Take a look at the Object Ordering section of the Oracle Java tutorials for more detail.
To expand on above comments, you should implement Comparable for any class T that you want to be able to compare/sort with other objects of type T. The interface has only one method you must implement, the compareTo function which should return a negative, positive, or zero value. You can then use this function in your generic class for T when it implements Comparable.
https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html
You should implement the Comparable but also the getSmallest should become the compareTo(T o) method.
Check the javadoc for the interaface here: https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html
In the code below Comparable interface is used to ensure x and y should be of same reference type but as V is extending T so V should be of the same type as T or subclass of T then what is the point of using Comparable interface.
Also if I am not using Comparable interface then the last call to isIf method is getting compile despite x and y are of different types.
Can anyone explain the use Comparable interface regarding this program?
public class Generics_13 {
static <T extends Comparable<T>, V extends T> boolean isIn(T x, V[] y) {
for(int i = 0;i < y.length;i++)
if(x.equals(y[i])) return true;
return false;
}
public static void main(String[] args) {
Integer nums[] = {10, 20, 30};
if(isIn(10, nums))
System.out.println("10 belongs to the array");
if(!isIn(60, nums))
System.out.println("70 doesnt belong to the array");
String arr[] = {"Neeraj", "Parth", "Ritum"};
if(!isIn("abc", arr))
System.out.println("abc doesnt belongs to the array");
/*if(isIn("String", nums)) // illegal
System.out.println("This wont compile");
*/
}
}
The current use of generics doesn't really makes sense, because no method from Comparable is ever used, which means that you could simply remove the extends declaration.
Also the Type V is also not used, as you can simply replace it by T and not break your logic. so the final result would look like this:
public class Generics_13 {
static <T> boolean isIn(T x, T[] y) {
for(int i = 0;i < y.length;i++)
if(x.equals(y[i])) return true;
return false;
}
// main() etc follow here
}
But now that we have the Stream API in java-8 you can use the following snippet to achieve the same thing:
static <T> boolean isIn(T x, T[] y) {
return Arrays.stream(y).anyMatch(i -> i.equals(x));
}
The comparable here in your scenario is optional.
T extends Comparable<T>
What this means is that whatever value you are passing should implement the interface comparable.
which basically means that the type parameter can be compared with other instances of the same type.
Now you might be wondering that since you are passing primitive data types, then how does the code not throw an error?
The reason for this is that the primitives are autoboxed to wrapper objects which implement Comparable.
So your ints become Integer and String is already an object both of which implement Comparable.
PS : your code will also work for objects provided that the class implements comparable
If I have a class that uses a template <T> how do I compare two variables of type T? One of my friends told me that you should add <T extends Comparable<? super T>> to your class in order to compare type T variables, but I dont competely understand what he ment. Here is my class:
public class SomeClass<T extends Comparable<? super T>>
{
public SomeClass(){}
public T foo(T par, T value)
{
if(value > par)
{
return value
}
else
{
return par;
}
}
}
And in my Main.java:
SomeClass<Integer> sc = new SomeClass<Integer>();
Integer val1 = 10;
Integer val2 = 5;
System.out.println(sc.foo(val1, val2));
The error i get is:
error: bad operand types for binary operator '>' if(value > par)
Your T implements Comparable, so you should use its compareTo() method.
if (value.compareTo(par) > 0) {
....
}
Also, note that in java it is called Generics, and not Templates, and is quite different from C++ templates (much weaker and much less complicated from the C++ version). One important difference is it does not work on primitives, only on objects - so if you wanted to use SomeClass<int> - that's impossible. (You could use SomeClass<Integer> however).
Also note, you cannot assign
T = 0;
Since T is an object.
> operator can be used only on primitives and not on objects. You need to use compareTo method for comparing objects.
Hi I'm trying to compare two objects using by extending the generics with the interface Comparable:
public class Tree<K extends Comparable<K>>
{
Node<K> treeNode;
// Some initialization stuff
public void test(Node<K> node)
{
// Some code
// This line fails
if(node.getKey() > treeNode.getKey())
{ ... }
// Rest of the code
}
}
public interface Node<K extends Comparable<K>>
{
// Some code
public K getNode();
// Some more code
}
But some reason, the compare operator is not recognized. I thought that by extending comparable I could begin using such an operator. What am I doing wrong. Thanks.
Comparable doesn't let you use < or > to compare, just like List and Map don't let you use [] for item access. You need to call the compareTo method, which will indicate the result of the comparison by returning an integer less than, greater than, or equal to 0.
There is no operator overloading in Java. Therefore, you can't use > even if the objects implement Comparable. You have to use compareTo() instead.