Understanding generics and comparable in Java - java

I am struggling with creating generic data types that require that its element to be comparable.
I have attempted to construct what I think is the most basic implementation of this, and it still is not working.
public class GenericPair<T> {
T thing1;
T thing2;
public GenericPair(T thing1, T thing2){
this.thing1 = thing1;
this.thing2 = thing2;
}
public <T extends Comparable<T>> int isSorted(){
return thing1.compareTo(thing2);
}
public static void main(String[] args){
GenericPair<Integer> onetwo = new GenericPair<Integer>(1, 2);
System.out.println(onetwo.isSorted());
}
}
My understanding is that > requires that whatever type T ends up, it must implement comparable and therefore must have a compareTo() function. In this case Integers should have this functionality right?
I am getting the error:
GenericPair.java:15: error: cannot find symbol
return thing1.compareTo(thing2);
^
symbol: method compareTo(T)
location: variable thing1 of type T
where T is a type-variable:
T extends Object declared in class GenericPair
What is going on here?

public <T extends Comparable<T>> int isSorted(){
return thing1.compareTo(thing2);
}
This new T is hiding the type parameter of your class (also called T). They are two different types! And thing1 and thing2 are instances of your class's generic type, which aren't necessarily comparable.
So, you should declare your class's type parameter to be comparable instead:
class GenericPair<T extends Comparable<T>>
And now:
public int isSorted(){
return thing1.compareTo(thing2); // thing1 and thing2 are comparable now
}

The problem is that generic T for the whole class doesn't know a compareTo method. Even if you declare <T extends Comparable<T>> for this single method, you're just creating a new T that hides the definition of the generic T from the class.
A solution may be declaring T extends Comparable<T> in the class itself:
class GenericPair<T extends Comparable<T>> {
public int isSorted() {
return thing1.compareTo(thing2);
}
}

public <T extends Comparable<T>> int isSorted(){
return thing1.compareTo(thing2);
}
You can't have a method that imposes new constraints on the generic type parameter defined by the class. You would have to declare
public class GenericPair<T extends Comparable<T>> {
public int isSorted() {
return thing1.compareTo(thing2);
}
}

Related

Java Generics - inserting inner type parameter

I am new to java. I am just trying to pass Comparable<String> into a method parameter of generic type <E extends Comparable<E>> . I believe the meaning of <E extends Comparable<E>> is any object that extends Comparable. Please let me know how to pass Comparable<String> or any object that extends Comparable<String> and has an other object in it.
Compiler is giving me error The inferred type Compare<String> is not a valid substitute for the bounded parameter <E extends Comparable<E>>
Code:
public class Compare<T> implements Comparable<T>{
public int compareTo(T o) {
return 0; // Not worried about logic
}
}
class CompareTest{
public <E extends Comparable<E>>void testGeneric(E e){
System.out.println("Executed");
}
public static void main(String args[]){
Compare<String> compare = new Compare<String>();
CompareTest test = new CompareTest();
test.testGeneric(compare);
//The inferred type Compare<String> is not a valid substitute for the bounded
//parameter <E extends Comparable<E>>
}
}
E extends Comparable<E> means: a type E that is able to compare to other objects of the same type E.
But your Compare type doesn't qualify. It can't compare with another Compare. A Compare<T> can only compare itself to a T, and not to a Compare<T>, since it's declared as
public class Compare<T> implements Comparable<T>
It's quite hard to understand what you want to achieve with this Compare type.
Your method
public <E extends Comparable<E>> void testGeneric(E e){
expects a type E that is a sub type of Comparable<E>. But you are passing it a Compare<String> which is not a sub type of <Comparable<Compare<String>>, but a sub type of Comparable<String>.
You'll have to clarify what you are trying to do if you need more help.
The error in my IDE says:
Inferred type 'Compare<java.lang.String>' for type parameter 'E' is not within its bound;
should implement 'java.lang.Comparable<Compare<java.lang.String>>'
It seems that E is inferred as Compare<String> instead of String. To get E to be String, try this:
public <E extends Comparable<E>> void testGeneric(Comparable<E> e){
To define a class as being comparable, the generic parameter to Comparable must be the class itself:
public class MyComparable implements Comparable<MyComparable> {
public int compareTo(MyComparable o) {
return 0;
}
}
Applying that to your class, you get the following code (which compiles):
public static class Compare<T> implements Comparable<Compare<T>> {
public int compareTo(Compare<T> o) {
return 0; // Not worried about logic
}
}
class CompareTest {
public <E extends Comparable<E>> void testGeneric(E e) {
System.out.println("Executed");
}
}
public static void main(String[] args) {
Compare<String> compare = new Compare<String>();
CompareTest test = new CompareTest();
test.testGeneric(compare);
}

Declare attribute of type that extends 2 different interfaces

I would like to declare attribute that holds instance of class that implements 2 different interfaces. I have tried this syntax:
private <? extends Interface1 & Interface2> name;
and this:
private <T extends Interface1 & Interface2> T name;
None of those work. Is it possible? What's the syntax? I'm trying to avoid declaring another interface that inherits from both Interface1 and Interface2.
Edit:
The class containing this attribute should not have any type arguments. That is nothing like this:
public class MyClass<T extends Interface1 & Interface2>{
private T name;
...
}
It would not make any sense for those using the class. It is not expected neither logical not possible for that class to be generic.
That needs to go in the class declaration, such as:
public class TestG<T extends Cloneable & Serializable> {
private T name;
}
One alternative is to set it in a method (but not a variable)
public class TestG {
public <T extends Cloneable & Serializable> void method(T parameter) {
}
}
A variable cannot be generic.
private <T> T var;
is not possible - at which point is T defined? When accessing var, I cannot make much assumptions on what I used at assignment time.
Java allows generics on classes and on methods. So you can have
private <T implements Cloneable & Serializable> void setVar(T val);
and you can have a class-wide type T.
But always remember that in the end, it is implemented by type erasure. You can always emulate more complex logic using getters, setters and casts. When done properly, it will give you just as much type safety.
The simplest way to obtain a variable with the type safety you want is to just use two variables, and a setter to keep them in sync.
private Serializable vars;
private Cloneable vars;
will of course give you a good type safety. But yes, it needs 4 bytes of additional memory, and a setter.
Here's the casting approach you asked:
private Object internal_var;
// Implementation notice: do not remove this generic.
// Due to a Java limitation, we *do* want these two constraints!
public <T extends Serializable & Cloneable> void setVar(T val) {
internal_var = val;
}
public Serializable getSerializable() {
return (Serializable) internal_var; // Type checked in setter!
}
public Cloneable getCloneable() {
return (Cloneable) internal_var; // Type checked in setter!
}
// This is the way to use it in a generic getter:
public <T extends Serializable & Cloneable> T getVar(Class<? super T> cls) {
return (T) cls.cast(val);
}
Note that in order to use T in the getter, we do need to have a parameter involving T.
Assuming we know a class Example implements Serializable, Cloneable, we can then use
// This actually ensures we get an instance of `Example` out:
Example e = instance.getVar(Example.class);
You can declare that type parameter in your class declaration, or method declaration, if that is a local variable, and use that type instead: -
public class Demo<T extends Interface1 & Interface2> {
private T t;
}
or: -
public class Demo {
public <S extends Interface1 & Interface2> void demo(S param1) {
S param;
}
}
If i understand your question correctly, you want a generic class which implements both the inetrfaces.
declare a generic type argument in your class definition and make it as an instace variable type.
public class Implementor<T extends Interface1<T> & Interface2<T>> {
private T t;
}
EDIT:
you cannot declare a type argument at instance variable declaration like
private <T extends I1 &I2> T t; //this cant be achieved.
at method level though is possible.
public <T extends I1 & I2> void method(T t){
}

Java Collection compare generic class that extends interface that extends comparable

I have this interface
public interface IDataPoint<T> extends Comparable<T> {
public T getValue();
}
and this implementation...
public class IntegerDataPoint implements IDataPoint<Integer> {
// ... some code omitted for this example
public int compareTo(Integer another) {
// ... some code
}
}
and another class...
public class HeatMap<X extends IDataPoint<?> {
private List<X> xPoints;
}
Now I would like to use Collections.max (and similar) on the xPoints list, but that does not work, probably because I got my generics all messed up.
Any suggestions how this could be solved (without a Comparator)?
Collections.max(xPoints);
gives me this error:
Bound mismatch: The generic method max(Collection<? extends T>) of type Collections is not applicable for the arguments (List<X>). The inferred type X is not a valid substitute for the bounded parameter <T extends Object & Comparable<? super T>>
The problem is that Collections.max(Collection<? extends T>) wants the T's to be comparable to themselves not some other type.
In your case IntegerDataPoint is comparable to Integer, but not IntegerDataPoint
You cannot easily fix this because IntegerDataPoint is not allowed to implement Comparable<Integer> and Comparable<IntegerDataPoint> at the same time.

question about interfaces and generics in Java: type mismatch error

Suppose I have the following interface:
public interface Interface<T extends Number>{
public Vector<Interface<T>> getVector();
}
and the following class implementing that interface:
public abstract class C<T extends Number> implements Interface<T>{
private Vector<C<T>> vector;
public Vector<Interface<T>> getVector(){ //errror
return this.vector;
}
}
Why is not legal returning a Vector<C<T>> meanwhile is legal ( obviously) returning a Vector<Interface<T>>. C is actually implementing Interface, so it should be possible, right? What am I missing?
EDIT:
why this work for non generics interface? Is this actually a generic related problem?
public interface Interface{
public Interface getVector();
}
public abstract class C implements Interface {
private C;
public Interface getVector(){ //errror
return this.c;
}
}
Because the Vector is explicitly made up of Interface<T>, not things that extend Interface<T>, I believe this would work if you changed the definition to
public Vector<? extends Interface<T>> getVector();
The problem is that for some V implements T or V extends T that Foo<V> is not a supertype of Foo<T>. The compiler does not test inheritance on the generic arguments unless you explicitly indicate that extension point.
Using Vector<? extends Interface<T>> means "allow any class that implements or extends Interface<T>, whereas Vector<Interface<T>> means a vector consisting only of Interface<T> items.
Perhaps it's more concrete to consider that List<Integer> is not an acceptable replacement for List<Number> despite Integer extending Number for precisely the same reason.
update:
I tested this and the following compiles without any errors or warnings
interface Interface<T extends Number>{
public Vector<? extends Interface<T>> getVector();
}
abstract class C<T extends Number> implements Interface<T>{
private Vector<C<T>> vector;
public Vector<? extends Interface<T>> getVector(){
return this.vector;
}
}
It's the way generics work. They are not "covariant": if you have class AClass and its subclass SubAClass, Vector<SubAClass> is not a subclass of Vector<A>. (Note however that SubAClass[] is a subclass of AClass[].)
EDIT:
The seemingly obvious:
public ArrayList<Object> blah() {
return new ArrayList<String>();
}
won't compile because ArrayList<String> is not a subclass ArrayList<Object>. So in your case you can't return a Vector<C<T>> instance for a Vector<Interface<T>>.

Java interface extends Comparable

I want to have an interface A parameterised by T A<T>, and also want every class that implements it to also implement Comparable (with T and its subtypes). It would seem natural to write interface A<T> extends Comparable<? extends T>, but that doesn't work. How should I do it then?
When Comparable<? extends T> appears it means you have an instance of Comparable that can be compared to one (unknown) subtype of T, not that it can be compared to any subtype of T.
But you don't need that, because a Comparable<T> can compare itself to any subtype of T anyway, e.g. a Comparable<Number> can compare itself to a Comparable<Double>.
So try:
interface A<T> extends Comparable<T> {
// ...
}
or
interface A<T extends Comparable<T>> extends Comparable<A<T>> {
// ...
}
depending on whether you need to be able to compare instances of T in order to implement your compareTo method.
If you use comparable you do not need to specify the possibility for subtypes in the compare function, it is by nature possible to pass in any subtype of an object X into a method that declared a parameter of class X. See the code below for more information.
public interface Test<T> extends Comparable<T> {
}
class TestImpl implements Test<Number> {
#Override
public int compareTo(final Number other) {
return other.intValue() - 128;
}
}
class TestMain {
public static void main(final String[] args) {
TestImpl testImpl = new TestImpl();
testImpl.compareTo(Integer.MIN_VALUE);
}
}

Categories