I tried to add interface Comparable to class SimpleEntry by subclass it. Because SimpleEntry is a generic type, I used this:
public class SimpleEntryComparable<K, V> extends SimpleEntry<K, V> implements
Comparable<T> {
public SimpleEntryComparable(K arg0, V arg1) {
super(arg0, arg1);
// TODO Auto-generated constructor stub
}
}
And eclipse complained "T cannot be resolved to a type".
I'm confused about subclass a generic class and add interfaces... anyone can tell me something about this?
chrylis' answer is correct. Below it I see you have this comment:
But in compareTo(), I want to "return o.getKey() - this.getKey();"
Based on this comment, it sounds like you want the following:
public class SimpleEntryComparable<K extends Comparable<? super K>, V>
extends SimpleEntry<K, V>
implements Comparable<SimpleEntryComparable<K, V>> {
#Override
public int compareTo(final SimpleEntryComparable<K, V> other) {
return getKey().compareTo(other.getKey());
}
}
This ensures that K is comparable to itself (or some super-type of itself), so that your code can delegate to that type's compareTo implementation. This is the only way to do generic comparisons of reference types - as chrylis points out, arithmetic operations are only supported for primitives.
The <T> on Comparable tells the compiler what type the class can be compared to. In your case, if you want to be able to compare to other SimpleEntryComparables, you just need implements Comparable<SimpleEntryComparable<K,V>> (and compareTo, of course!).
Related
I'm trying to create an implementation of Map that takes collections as keys.
What do you even call this conundrum?
What is the right way to do the class signature?
class SubClass <K extends Collection<E>, V> implements Map<K, V>
^^ Is improper syntax, but indicates what I want to do.
class SubClass <K extends Collection<K>, V> implements Map<Collection<K>, V>
^^ Results in a SubClass for which you can never declare the generic type. K is infinitely recursive. It also doesn't describe the type of behavior I'm looking for.
class SubClass <K , V> implements Map<K, V>
^^ Doesn't enforce the constraint that K needs to be a Collection
class SubClass <K extends Collection, V> implements Map<K, V>
^^ Doesn't allow us to know the generic types of the Collection
class SubClass <E, K extends Collection<E>, V> implements Map<K, V>
^^ Works, but is rather unwieldy
You'll need a type parameter for the Collection element type, potentially a type parameter for the actual Collection type if you need it, and a type parameter for the values.
class SubClass<E, K extends Collection<E>, V> implements Map<K, V> { ... }
If you don't need the specific Collection type, you can use
class SubClass<E, V> implements Map<Collection<E>, V> { ... }
Concerning the various comments on your question
public class Example {
public static void main(String[] args) throws Exception {
Whatever<Self> s = new Whatever<>();
}
}
class Self extends ArrayList<Self> {
}
class Whatever<E extends Collection<E>> {
}
I use comparable interface all the time to provided natural ordering for my class through collection.sort.
Basically if I have a person class, I will get it to implement Comparable interface and will provide the implementation of compareTo. However in the definition of Collections.sort in javadocs, I see this signature
public static <T extends Comparable<? super T>> void sort(List<T> list)
I don't understand this generics definition at all? Shouldn't it just say
<T implements Comparable<T>>
Can someone help me with this?
Actually, it means that T can implement Comparable<? super T>, not just Comparable<T>.
For example, it means that a Student class can implement Comparable<Person>, where Student is a subclass of Person:
public class Person {}
public class Student extends Person implements Comparable<Person> {
#Override public int compareTo(Person that) {
// ...
}
}
In this case, a List can be sorted by Collections.sort() but only based on Person's properties, because you pass the Student instance into compareTo() as a Person (unless you downcast it, of course).
In practice however, you'll never see a Student class implement Comparable<Person>. That's because Person will probably have implemented Comparable<Person>, and Student inherits it implementation. The end result is the same however: you can pass a List<Student> to Collections.sort() and have it sorted on Person's properties.
The difference between Comparable<T> and Comparable<? super T> is more obvious in the overloaded version of Collections.sort() that takes a Comparator<? super T>:
class ByAgeAscending implements Comparator<Person> {
#Override public int compare(Person a, Person b) {
return a.getAge() < b.getAge();
}
}
List<Student> students = getSomeStudents();
Collections.sort(students, new ByAgeAscending());
You always use extends with generics wildcards, even if the type parameter implements an interface.
If you look at a class that implements Comparable, you'll see that it actually (should) implement Comparable<T>, where T is the class itself.
It makes sense if you think about the type paramter passed to the Comparable interface and how it's used in the compareTo() method.
As PM 77-1 has eloquently pointed out, the super keyword allows for either the class, T, or one of its parents to implement Comparable.
private interface Internal {
<T extends Comparable<? super T>> void compare(final T left, T right);
}
private final Internal internal = ...;
public <T> void compare(final Comparable<T> left, final Comparable<T> right) {
this.internal.compare(left, right);
}
I'm seeing a compiler error on .compare(left, right):
Bound mismatch: The generic method compare(T, T) of type
MyClass.Internal is not applicable for the arguments
(Comparable<T>, Comparable<T>). The inferred type Comparable<T> is not a valid
substitute for the bounded parameter <T extends Comparable<? super T>>
Is there any reasonable way to accomplish the transition I'm trying to make - taking in Comparable from the public-facing method and using it in a type-safe manner in the internal implementation? Or do I need the same type information for my outer method as I have for the inner one?
Comparable is just defined as:
public interface Comparable<T>
It means that implementing classes can compareTo anything they want. So for example I can do this:
class Vague
implements Comparable<String> {
#Override
public int compareTo(String str) {
return 0;
}
}
When you have a type as:
<T extends Comparable<? super T>>
It means that T must be a Comparable that also compares to a T or superclass of T.
On the other hand, when you just have <T> and then Comparable<T> it can be a Comparable that compares to anything.
The class Vague is a Comparable<T> but not a T extends Comparable<? super T>. Obviously Vague is not a good Comparable.
So yes, these are inconvertible types and the method signatures will have to be made to match. <T extends Comparable<? super T>> is the type safe way to declare a Comparable parameter generically. It means two instances of T can be compared to each other.
I have a method:
public List<Stuff> sortStuff(List<Stuff> toSort) {
java.util.Collections.sort(toSort);
return toSort;
}
This produces a warning:
Type safety: Unchecked invocation sort(List<Stuff>) of the generic method sort(List<T>) of type Collections.
Eclipse says the only way to fix the warning is to add #SuppressWarnings("unchecked") to my sortStuff method. That seems like a crummy way to do with something that is built into Java itself.
Is this really my only option here? Why or why not? Thanks in advance!
Collections.sort(List<T>) expects that T must implement Comparable<? super T>. It seems like Stuff does implement Comparable but doesn't provide the generic type argument.
Make sure to declare this:
public class Stuff implements Comparable<Stuff>
Instead of this:
public class Stuff implements Comparable
Do tou use this:
// Bad Code
public class Stuff implements Comparable{
#Override
public int compareTo(Object o) {
// TODO
return ...
}
}
or this?
// GoodCode
public class Stuff implements Comparable<Stuff>{
#Override
public int compareTo(Stuff o) {
// TODO
return ...
}
}
You will need to change the return type of your method
Sorting Generic Collections
There are two sorting functions defined in this class, shown below:
public static <T extends Comparable<? super T>> void sort(List<T> list);
public static <T> void sort(List<T> list, Comparator<? super T> c);
Neither one of these is exactly easy on the eyes and both include the wildcard (?) operator in their definitions. The first version accepts a List only if T extends Comparable directly or a generic instantiation of Comparable which takes T or a superclass as a generic parameter. The second version takes a List and a Comparator instantiated with T or a supertype.
It might sound like reinvention of wheel, but I am trying to implement a map, (like Map<K,V>). The class has a function called sortedKey() which returns an ArrayList<K> A cut-down version of my code is below. I have included my attempts to debug inline as comments.
import java.util.ArrayList;
import java.util.Collections;
public class Map<K,V> {
private ArrayList<Pair<K,V> > array; //Pair<K,V> is a class defined in another file.
//returns an ArrayList(of proper type) of keys (ie, the desired function)
public ArrayList<K> sortedKeys(){
ArrayList<K> ret = keys(); //another method defined inside same class
K s = ""; // error: no suitable method found for sort(ArrayList<K>)
Collections.sort(new ArrayList<String>()); //Works just fine..
Collections.sort(ret); //Same error here..
return ret;
}
}
Any idea on why is that error showing up? Can I not have generic return types depending on the type-variable used in creation of the class? Or do I have to do something else to achieve the desired effect?
Thanks and apologies if this question has already been asked
Cajetan
Have a look at the signature of Collections.sort:
public static <T extends Comparable<? super T>> void sort(List<T> list)
So the error, though it might be confusing, is right - you can't call sort on a list of arbitrary type; the element type must implement Comparable.
If you restrict your generic parameter to be comparable, as in:
public class Map<K extends Comparable<K>,V> {
...
then the call to Collections.sort(ret) will succeed as you expect.
Without this restriction on the generic parameter, someone could create a Map with a key type of something noncomparable like Exception - and then how do you expect poor Collections.sort to handle that? :)
The compiler is telling you that K might not be a type with an ordering. You should declare the class as
public class Map<K extends Comparable<K>, V> {
to guarantee that K values can be compared to other K values.
From the Javadoc for Collection.sort() the type has to be
public static <T extends Comparable<? super T>> void sort(List<T> list)
In other words, K has to be declared as Comparable<K> or Comparable<? super K>
Well...you should provide a comparator or implements comparable by your K(whichever it may be) class.
in case of implementing comparable, Also declare class parameter like this to restrict it to contain only comparable object.
public class Map<K extends Comparable<K>, V>