I would like to understand what this Java declaration is doing:
public static <AnyType extends Comparable<? super AnyType>> int mymethod( AnyType x ) {
/* ... */
}
From my basic knowledage of Java, I think all it's doing is telling you that the param x must be of any type, but that type must extend Comparable?
Your understanding is correct. This method indicates that it takes an argument of a type that extends a Comparable (Note that I would have called the type parameter T instead of AnyType for readability).
Now for the super in Comparable<? super AnyType>>, it means that this comparable implementation can actually be, for example, an implementation of Comparable<Object>, that is a comparable type that can be compared to an object. More generally, the type accepted by the method can be a Comparable which can be compared to some type that is a superclass or superinterface of it, hence the keyword super. In other words, the method can be invoked as follows:
// An object of this type can be compared to an Object
class X implements Comparable<Object> {
#Override
public int compareTo(Object o) {
...
}
}
X x = new X();
mymethod(x);
This is a generic method, i.e. its type parametrization is not related to the class' parametrization if any.
The <AnyType extends Comparable<? super AnyType>> part is the generic parametrization of the method.
The extends keyword should not be confused with the extends keyword when declaring a class: in this case it looks more like "is assignable from", in other words, IS-A.
Comparable<T> is an interface - see docs here.
Your method parametrization will make it so that your method accepts any parameter, as long as its type implements Comparable.
Specifically, it needs to be a Comparable of itself or any super-type (that's what the super part means, as opposed to extends).
For instance, you can pass a String argument because String implements Comparable<String> (amongst others).
Yes, parameter must be a sub-type of Comparable.
Related
TreeSet(Collection<? extends E> c) constructor was defined as:
Constructs a new tree set containing the elements in the specified collection, sorted according to the natural ordering of its elements. All elements inserted into the set must implement the Comparable interface. Furthermore, all such elements must be mutually comparable: e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the set.
Is it possible syntactically enforce that E in Collection<? extends E> implements Comparable? In above JavaDoc this check postponed to execution time...
Yes, but not with constructors; you'd have to expose a factory method, which can impose constraints on the collection type beyond those imposed by the class as a whole. For example, they could've written
public class TreeSet<E> { ...
public static <E extends Comparable<? super E>> TreeSet<E>
create(Collection<? extends E> collection) {
TreeSet<E> set = new TreeSet<E>();
set.addAll(collection);
return set;
}
...
}
You can make your project require this by using a factory method like this:
public static <T extends Comparable<? super T>> SortedSet<T> safeSortedSet() {
return new TreeSet<T>();
}
Then is code:
Set<String> pass = safeSortedSet();
Set<Foo> fail = safeSortedSet();
Second line produces compile error:
Error:(99, 38) java: incompatible types: inference variable T has incompatible bounds
equality constraints: Test.Foo
upper bounds: java.lang.Comparable
From Tavian Barnes comment:
They could have done class TreeSet<E extends Comparable<? super E>>, but then you wouldn't have been able to use custom comparators for unorderable types. I can't think of a good way to enforce this only on a single constructor
So it is possible with <E extends Comparable<? super E>> syntax, but unfortunately each generic extends / super syntax make ultimate restriction on any other type declaration with E.
In case TreeSet look to Creating a TreeSet with a non-Comparable class: why a run-time exception, rather than compile-time error?
Thanks for all who helps with answer!
Could anyone please help me understand how does Java's generics work? I understand the concept of it. But for this specific example of the code I don't clearly understand the compiler's error messages.
Example code:
Test class
// Test code
public class A < ListType extends Comparable < ListType >> {
// To make the instance variable y
public int y;
// To make the instance variable s
public String s;
//Constructor Method
public A(int requiredY, String requiredS) {
y = requiredY;
s = requiredS;
}
more code here...
}
Then in a different class I wrote
List <A> a = new ArrayList<A>();
more code here...
Collections.sort(a)
The error message I am getting is
test.java:20: error: no suitable method found for sort(List<A>)
Collections.sort(a);
^
method Collections.<T#1>sort(List<T#1>) is not applicable
(inference variable T#1 has incompatible bounds
equality constraints: A
upper bounds: Comparable<? super T#1>)
method Collections.<T#2>sort(List<T#2>,Comparator<? super T#2>) is not applicable
(cannot infer type-variable(s) T#2
(actual and formal argument lists differ in length))
where T#1,T#2 are type-variables:
T#1 extends Comparable<? super T#1> declared in method <T#1>sort(List<T#1>)
T#2 extends Object declared in method <T#2>sort(List<T#2>,Comparator<? super T#2>)
I don't understand why is the compiler complaining about the type parameter. Shouldn't the collections work? Because the type parameters are both mutually comparable.
Either you're writing your question wrong in order to hide the class names, or you're mistaken in representing the generics.
If what you're trying to do is making a class that could be sorted, you can implement Comparable in the class A as others have suggested.
public class A < ListType extends Comparable < ListType >> {
...
}
The above code would require the class A to accept a class that extends/implements Comparable, and use ListType as its type erasure.
Since you don't show how would you use the ListType to bound a type, I don't think this is what you want.
Usually generics are used to bound the type of parameter you can use in a class, in order to provide a type-safe operations in compile time.
import java.lang.Override;
public class A <ListType extends Comparable<ListType>>{
ListType lt;
A(ListType b){
this.lt = b;
}
static class B implements Comparable<B>{
B(){};
#Override
public int compareTo(B b){
return 0;
}
}
static class C implements Comparable<B>{
C(){};
#Override
public int compareTo(B c){
return 0;
}
}
public static void main(String[] args){
A<B> a = new A<B>(new B()); //OK
A<C> _a = new A<C>(new C()); //ERROR: is not within bound
System.out.println("");
}
}
Because class C is not implementing a Comparable class with itself, you cannot pass a class C variable to the class A constructor.
If you want to create a type that will accept any classes that extends Comparable, you could use a wildcard ?.
public class A <ListType extends Comparable<?>>
or use a single capital letter as type for better code styling
public class A <T extends Comparable<?>>
Your issue is that A is not Comparable. Notice your type signature:
public class A<ListType extends Comparable<ListType>>
This says that A (which is a poor name for a concrete class, single-letter types are generally reserved for generic types) has a generic type ListType, and that ListType is Comparable with other ListType objects.
The signature of Collections.sort() expects to be passed a List<T> where T is a generic type that implements Comparable. Since A does not implement Comparable you cannot pass it to Collections.sort().
You likely did not mean to define A the way you did. You probably intended to do something like this:
public class A<ListType> implements Comparable<A<ListType>>
This says both that A has a generic type called ListType and that A implements Comparable and therefore can be compared (and sorted) with other instances of A.
Since A now implements the Comparable interface you'll need to define a
compareTo() method on A.
You should check how to use the Comparator Interface.
To compare custom classes you need to implement your customized Comparator and then only you can use the Sorting method provided by the collections interface.
You can look here for reference.
I have a Generic method that should work similarly to recursion, but calling different instances of the method for each calling.
public <M extends A> void doSomething(Class<M> mClass, M mObject)
{
// ... Do something with mObject.
A object = getObject();
Class<? extends A> objectClass = object.getClass();
doSomething(objectClass, objectClass.cast(object)); // Does not compile.
}
private A getObject() {...}
The problem is the line with a comment does not compile, giving the following error:
The method doSomething(Class, M) in the type MainTest is not applicable for the arguments (Class, capture#3-of ? extends A)
I don't quite understand why the compiler does not compile if it can call doSomething with M = "? extends A".
Why doesn't it compile?
Ok here is a crude explanation
You've typed your method so that it will accept M which is a subtype of A
Now you are calling your method using 'objectClass' which is a subtype of A BUT not necessarily a subtype of M.
Hence the compiler is complaining...
If you can explain what you are trying to do a bit more, I can help with a solution.
The language does not track wildcards like that (it seems). What you need to do is to capture that wildcard, which can be done with a method call with type inference.
public <M extends A> void doSomething(Class<M> mClass, M mObject) {
// ... Do something with mObject.
A object = getObject();
Class<? extends A> objectClass = object.getClass();
privateSomething(objectClass, object);
}
private <T extends A> void privateSomething(Class<T> objectClass, A object) {
doSomething(objectClass, objectClass.cast(object)); // Should compile.
}
As always, whilst reflection has some uses, it's usually a sign of confusion.
When you are asking the compiler to perform a cast, the exact type to perform the cast must be known. It is not sufficient to tell the compiler that you don't know about the exact type excerpt that it's a subclass of A.
Class tell the compiler that the type of the object is a subclass of A but it doesn't tell the compilator the exact type to be used for the casting.
Your problem is that you are trying to replace Polymorphism with Generic. As you are learning the hard way, Generic is not the new modern way of doing Polymorphism.
I have some sorting methods that in order to work they need to accept an object that has the compareTo defined.
The following as part of the generic definition:
private static <SomeType extends Comparable<? super SomeType>>
void doSomeSort(SomeType[] a, int left, int right){
seems to do the trick.
My problem is that I don't really understand what the
<SomeType extends Comparable<? super SomeType>>
actually defines.
It means that you can substiture a type that is an interface that extends Comparable that is instanciated by itself...
I don't get.
Can you please help on clarifying this definition?
This means:
SomeType is a class that extends Comparable<SomeType> or Comparable<Any type that is a superclass or super interface of SomeType>.
The reason of ? super SomeType is that the sort procedure is able to sort an array of SomeType instances if SomeType is able to compare itself to other SomeType instances. If it happens that SomeType extends SomeSuperType, and that any SomeSuperType instance is able to compare itself to other SomeSuperType instances, the sort will compare them without problems.
Ultimately, all you really need to know is that it means:
SomeType x = ...;
SomeType y = ...;
int comparison = x.compareTo(y);
will compile.
More precisely, it means that SomeType implements Comparable<T> for some type T which is in the inheritance hierarchy of SomeType... without you having to specify what the T is but the upshot is that the code above works :)
It translates to:
the type SomeType must extend or implement the class Comparable
the class Comparable itself, in this case, takes some type as parameter, let's call it T.
type T must be SomeType or a superclass of SomeType.
A classic type that fits this pattern is Integer, since it implements Comparable<Integer>.
<SomeType extends Comparable<? super SomeType>>
Comparable is always of a special template type.
So Comparable<String> is something that can be compared to a String, Comparable<BigInteger> is something that can be compared to a BigInteger, and so on.
What's expected here is a SomeType which derives from Comparable<T>. Meaning that SomeType is comparable to other instances. The most trivial thing would be
<SomeType extends Comparable<SomeType>>
Should be clear till now.
Everything thats now added is a simple super keyword.
This means, SomeType needs to be comparable to everything that is of type SomeType or anything above in the derivation hierarchy.
This basically has one advantage: You can later derive your own/additional types from SomeType and this method will still be downward compatible!
Awesome, eh?
For example:
class SomeTypeSuper { ... }
class SomeType extends SomeTypeSuper { ... }
// Now, in your code both is valid:
// Asuming the method `yourMethod` expects a `<SomeType extends Comparable<? super SomeType>>` as parameter.
yourMethod(new SomeTypeSuper()); // This wouldn't be valid if we had used Comparable<SomeType>
yourMethod(new SomeType());
Float is a subclass of Number. We could declare it like so:
class Float extends Number implements Comparable<Float>
But in fact, our Float class is way broader than that. The float class knows how to compare itself with Integers, Bignums, Doubles, etc etc. In fact, our float class knows how to compare itself to *any( number.
class Float extends Number implements Comparable<Number>
class Integer extends Number implements Comparable<Number>
In fact: any number class needs to do this, so the real declaration sare
class Number implements Comparable<Number>
class Integer extends Number
class Float extends Number
Now, the Comparable interface is cool with this. If it wasn't wildcarded, then Floats and Integers wouldn't be able to be Comparable.
But since it is, you can go:
Comparable<Number> array[] = new Comparable<Number>[10];
array[0] = Float.getValue(10);
array[1] = Integer.getValue(11);
sort(array, 0, 1);
You can't do this without the >? super T>.
What is the difference in following 2 lines?
public static <T extends Comparable<? super T>> int methodX(List<T> data)
public static <T> int methodX(List<? extends Comparable<? super T>> data)
Your first option is a "stricter" parametrisation. Meaning, you're defining the class T with a bunch of restrictions, and then use it later on with List. In your second method, the parameter class T is generic with no conditions, and the Lists class parameter is defined in terms of the parameter T.
The second way is syntactically different as well, with a ? instead of the first option's T, because in the parameter definition you aren't defining the type parameter T but rather using it, so the second method cannot be as specific.
The practical difference that comes out of this is one of inheritance. Your first method needs to be a type that is comparable to a super class of itself, whereas the second type need only be comparable to an unconditional/unrelated T:
public class Person implements Comparable<Number> {
#Override
public int compareTo(Number o) {
return 0;
}
public static <T extends Comparable<? super T>> int methodX(List<T> data) {
return 0;
}
public static <T> int methodY(List<? extends Comparable<? super T>> data) {
return 0;
}
public static void main(String[] args) {
methodX(new ArrayList<Person>()); // stricter ==> compilation error
methodY<Object>(new ArrayList<Person>());
}
}
If you change the Comparable of Person to be able to compare Object or Person (the inheritance tree of the base class) then methodX will also work.
To the callers, the 2nd version is roughly equivalent to
public static <T, X extends Comparable<? super T>> int methodX(List<X> data)
Suppose a caller calls it with an arg whose concrete type List<Foo>. Type inference will conclude that X=Foo. Then we get a new equation about T from X's bound
=>
Foo <: Comparable<? super T>
( A <: B means A is a subtype of B)
If Foo is Comparable at all, it almost certainly implements Comparable<Foo> [2]
=>
Comparable<Foo> <: Comparable<? super T>
=>
T <: Foo
Without further information, inference chooses T=Foo.
Therefore from caller's POV, the two versions are not really different.
Inside method body, the 2nd version does not have access to type parameter X, which is a synthetic one introduced in compilation phase. This means you can only read from data. Things like
X x = data.get(0);
data.set(1, x);
are impossible in version#2; No such problem in version #1 with T.
However we can forward #2 to #1
<T1> method1(List<T1> data){ data.set(...); }
<T2> method2(List<?...> data)
{
method1(data);
}
(they must have difference method names; overloading not allowed since java7)
This is because for the compiler, type of data is really List<X> (it knows the secrete X), so there is no problem calling method1(data) after inferring that T1=X
[1] JLS3, 5.1.10 Capture Conversion
[2] According to the javadoc of Comparable, This interface imposes a total ordering on the objects of each class that implements it. That means if Foo implements Comparable<W>, W must be Foo or a super type of Foo. It is quite improbably for a subclass implementation to define a total order among objects of a super class. So W most definitely should be Foo. Otherwise funny things would happen. The notorious example is 'Timestamp', its javadoc (now) explains why it can't be compared with its supertype Date
The first method expects a list of elements which can be compared against their own class or a supertype of it. Say, real numbers can be compared to any kind of numbers:
class Real extends Number implements Comparable<Number> {
public int compareTo(Number o) ...
}
A bit more restrictive, but still acceptable for your first method is the following:
class Real extends Number implements Comparable<Real> {
public int compareTo(Real o) ...
}
But the second method is actually not very different from this version:
public static int methodY(List<? extends Comparable<?>> data) ...
That is to say, you can replace T with an unnamed wildcard ? because it is used only once in the method signature. It does not use concepts like the same class or an object's own class, etc.