I understand how to use the Comparable<T> interface, but in this specific example, I'm wondering if there is a way to require the inheriting Class from an Abstract Class (which implements the Comparable<T> interface) to be Comparable against itself.
Let me reiterate, there is an Abstract Class that implements the Comparable Interface:
public abstract class MyAbstractClass implements Comparable<MyAbstractClass>
And a Class which inherits from this Abstract Class:
public class MyClass extends MyAbstractClass
Typically with this setup, the following method is required to satisfy the Comparable Interface:
public int compareTo(MyAbstractClass otherAbstractObject)
This requires me to make the following cast:
public int compareTo(MyAbstractClass otherAbstractObject)
{
MyClass otherObject = (MyClass) otherAbstractObject;
// Comparison...
return result;
}
Given the fact that this cast could easily fail by trying to use a different child of MyAbstractClass, I would like to be able to define my Abstract Class to accept the following method:
public int compareTo(MyClass otherMyObject)
{
// Comparison...
return result;
}
And ideas on how to accomplish this? Or is it simply not possible?
You can define MyAbstractClass using generics as follows:
public abstract class MyAbstractClass<T extends MyAbstractClass<T>>
implements Comparable<T> {
Then you can define subclasses such as
public class MyClass extends MyAbstractClass<MyClass>
which allow you to define the compareTo method like this:
public int compareTo(MyClass otherMyClass)
However, that doesn't prevent anyone from writing a subclass that doesn't conform to the pattern:
public class SneakyClass extends MyAbstractClass<MyClass>
which would also define the compareTo method similarly:
public int compareTo(MyClass otherMyClass)
Note: There's nothing that can force the generic type parameter of a class to equal the class on which it's defined; the best you can do is to enforce an upper bound on the abstract class, to at least force it to be some kind of MyAbstractClass.
Related
I have a class like this :
public class MyClass <T extends Model1, X extends Model2> {
private CommonMessage<T,X> someMethod() {
....
}
}
Now I have a customized message type MyMessage extends CommonMessage, so I want to know how to have generic type that still having T and X as parameters ? For example :
public class MyClass <M extends CommonMessage, T extends Model1, X extends Model2> {
private M<T,X> someMethod() {
....
}
}
Short answer:
First of all as CommonMessage is generic, extending it in a non-generic way is very bad so you should have done M extends CommonMessage<T, X> And this way because type parameter passed to CommonMessage at class declaration you should not mention this parameter type again at method return type so method return type should be M.
Long answer:
I know you do know this definitions but sometimes we as human forget simple things. First we should consider what generics are created for, with generics we can create classes with different parameter types, this parameter types will be provided when they are extended by another class or when we create new instance of them with new() operator, so when we are writing our class we don't know the exact type for those parameter and we want to delay this decision until later, it is contradictory to something you are doing in your class because here your method is private and you can't change its implementation in your child class(the class which inherited from your class). But know we can change your implementation to something like this which will be compiled well:
public class MyClass<M extends CommonMessage<T, X>, T extends Model1, X extends Model2> {
private M method1(){
...
}
}
public class CommonMessage<T, X>{
}
public class MyMessage<T, X> extends CommonMessage<T, X>{
}
public class Model1{
}
public class Model2{
}
although this implementation will be compiled the problem is that when you are writing your private method(method1) you don't know what is the type of M at the time of writing this class because it will be passed when we want to create new instance of this class or when we inherit another class from this class. so what type of Object do you want to create and return in your method1? the only thing that you know here is that its type is M which extends CommonMessage but you don't know what the exact type of M is at the time of writing your private method(method1)!
And on the top of that you can't delegate this decision to your subclass(because this method is private). Now the question is that why it is allowed and compiled well when we don't know the exact type of M? for a moment forget this question I will make it clear after explaining correct approach. so what is the correct approach? Think about it, the person who write subclass does know exactly what the type of parameter M is and they can create appropriate instance of M in implementation of method1 to return from this method. so why not delegate this decision to subclass and making this method abstract? This completely make senses. in a nutshell we have some implementation like this:
public abstract class MyClass<M extends CommonMessage<T, X>, T extends Model1, X extends Model2> {
public abstract M method1();
}
public class CommonMessage<T, X>{
}
public class MyMessage<T, X> extends CommonMessage<T, X>{
}
public class Model1{
}
public class Model2{
}
now lets get back to our question why first program that I suggested to you compiled well? why we are allowed to have private method that its return type is generic that will be passed at instanciation or inheritance time?
because there are a lot of situations that make it correct and appropriate.
one situation is that our private method call another public method which return the appropriate type, like this:
public abstract class MyClass<M extends CommonMessage<T, X>, T extends Model1, X extends Model2> {
private M method1(){
return method2();
}
abstract M method2();
}
public class CommonMessage<T, X>{
}
public class MyMessage<T, X> extends CommonMessage<T, X>{
}
public class Model1{
}
public class Model2{
}
Following code is compiling absolutely fine.
To my understanding it should not be because Class C implementing interface I
as abstract class fails to compile as well.
interface I {
public String toString();
}
class C implements I {
}
Abstract class is not compiling
abstract class MyAbstractClass {
public abstract String toString();
}
public class MyClass extends MyAbstractClass {
}
Please help me understand this behavior why abstract is not compiling and interface does ?
Every class implicitly extends java.lang.Object, and java.lang.Object implements the toString() method. The interface's contract is satisfied by that implementation, thus removing the need for your class to provide its own implementation of toString().
The reason compilation fails for the abstract class is because you explicitly define the toString() method as abstract, thereby signaling that concrete extending classes are forced to provide their own implementation.
Consider that I have following interface:
public interface MyInterface<T extends Number>
In another class I want to declare a method like this:
public <T extends MyInterface<?>> void abc(T a);
Is this a correct way? Or maybe should I write:
public <T extends MyInterface<T>> void abc(T a);
What is the difference between these two declarations?
Some interfaces are intended to take the implementing class as the generic type.
For instance, the Comparable interface is usually implemented as:
class MyClass implements Comparable<MyClass>
because then the method
int compareTo(T o);
declared in Comparable can be used to compare an instance of MyClass to another instance of the same class.
Other interfaces have a generic parameter of a different type. For instance, List<T>, where T indicates the type of object contained within the list.
If you declare a method with:
public <T extends MyInterface<T>> void abc(T a);
then you're saying that the class T implements the interface MyInterface in the way that classes implement the Comparable interface - with themselves as the generic type. That might or might not be appropriate depending on what MyInterface actually is.
If you declare a method with:
public <T extends MyInterface<?>> void abc(T a):
then you not placing any constraint on the generic type in T's implementation of MyInterface.
The other option is
public void abc(MyInterface<?> a);
which is the simplest way to write a method that will accept any implementation of MyInterface.
Can someone please explain me this class definition statement
public class BinarTree<Type extends Comparable<Type>> {...
I completely understand the purpose of it but not the syntax. According to me it should be just
public class BinarTree<Type extends Comparable> {...
What's the meaning of
<Type extends Comparable<Type>> ?
^^^^
Comparable is a generic interface. The reason behind that is to avoid casting to a specific type in the Comparable#compareTo(...) method.
So if a Type extends Comparable<Type> this would mean that the Type will derive a method with signature
public int compareTo(Type t1)
instead of
public int compareTo(Object o1)
The interface Comparable is itself a template.
So what you have there is a template with a parameter that must extend a template.
And specifically it must extend a template that received the extending class as a parameter.
Comparable is a template for interfaces that implement an order relationship and implement the method int compareTo(TYPE o).
So it's normal to define a class:
class FooBar implements Comparable<FooBar> {...
A binary tree wouldn't work for a class that was declared:
class FooBar implements Comparable<Snafu> {...
That's because you would be able to compare FooBars to Snafus but not each other.
In
public class BinarTree<Type extends Comparable>{...
Type can be any Comparable, also Comparable<Integer> or Comparable<OtherType>. If this is what you want, it is fine. Most times, I think you know what you want to compare exactly, so specialize the Comparable to Comparable<Type>
I am trying to define an abstract class implementing Comparable. When I define the class with following definition:
public abstract class MyClass implements Comparable <MyClass>
subclasses have to implement compareTo(MyClass object). Instead, I want every subclass to implement compareTo(SubClass object), accepting an object of its own type. When I try to define the abstract class with something like:
public abstract class MyClass implements Comparable <? extends MyClass>
It complains that "A supertype may not specify any wildcard."
Is there a solution?
It's a little too verbose in my opinion, but works:
public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> {
}
public class SubClass extends MyClass<SubClass> {
#Override
public int compareTo(SubClass o) {
// TODO Auto-generated method stub
return 0;
}
}
Apart from the mechanical difficulties you're encountering declaring the signatures, the goal doesn't make much sense. You're trying to establish a covariant comparison function, which breaks the whole idea of establishing an interface that derived classes can tailor.
If you define some subclass SubClass such that its instances can only be compared to other SubClass instances, then how does SubClass satisfy the contract defined by MyClass? Recall that MyClass is saying that it and any types derived from it can be compared against other MyClass instances. You're trying to make that not true for SubClass, which means that SubClass does not satisfy MyClass's contract: You cannot substitute SubClass for MyClass, because SubClass's requirements are stricter.
This problem centers on covariance and contravariance, and how they allow function signatures to change through type derivation. You can relax a requirement on an argument's type—accepting a wider type than the supertype's signature demands—and you can strengthen a requirement on a return type—promising to return a narrower type than the supertype's signature. Each of these freedoms still allows perfect substitution of the derived type for the supertype; a caller can't tell the difference when using the derived type through the supertype's interface, but a caller using the derived type concretely can take advantage of these freedoms.
Willi's answer teaches something about generic declarations, but I urge you to reconsider your goal before accepting the technique at the expense of semantics.
see Java's own example:
public abstract class Enum<E extends Enum<E>> implements Comparable<E>
public final int compareTo(E o)
on seh's comment: usually the argument is correct. but generics makes type relations more complicated. a SubClass may not be a subtype of MyClass in Willi's solution....
SubClassA is a subtype of MyClass<SubClassA>, but not a subtype of MyClass<SubClassB>
type MyClass<X> defines a contract for compareTo(X) which all of its subtypes must honor. there is no problem there.
I'm not sure that you need the capture:
First, add the compareTo to the abstract class...
public abstract class MyClass implements Comparable <MyClass> {
#Override
public int compareTo(MyClass c) {
...
}
}
Then add the implementations...
public class MyClass1 extends MyClass {
...
}
public class MyClass2 extends MyClass {
...
}
Calling compare will call the super type method...
MyClass1 c1 = new MyClass1();
MyClass2 c2 = new MyClass2();
c1.compareTo(c2);
public abstract class MyClass<T> implements Comparable<T> {
}
public class SubClass extends MyClass<SubClass> {
#Override
public int compareTo(SubClass o) {
// TODO Auto-generated method stub
return 0;
}
}
Found another solution:
Define an interface on the fields which make up the comaprable (e.g ComparableFoo)
Implement the interface on the parent class
Implement Comparable on the parent class.
Write your implementation.
Solution should look like this:
public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
public int compareTo(ComparableFoo o) {
// your implementation
}
}
This solution implies that more things might implement ComparableFoo - this is likely not the case but then you're coding to an interface and the generics expression is simple.
I know you said you want "compareTo(SubClass object), accepting an object of its own type", but I still suggest declaring the abstract class like this:
public abstract class MyClass implements Comparable <Object>
and do an instanceof check when overriding compareTo in MySubClass:
#Override
public int compareTo(Object o) {
if (o instanceof MySubClass)) {
...
}
else throw new IllegalArgumentException(...)
}
similarly to 'equals' or 'clone'