It seems like you usually implemented the java.lang.Comparable interface without specifying the type parameter.
public abstract class Area implements Comparable {
#Override
public int compareTo(Object other) {
if (other instanceof Area)
return new Double(getArea()).compareTo(other.getArea());
return -1; // or something else
}
abstract public double getArea();
}
Since I only want to compare apples with apples, I think it would make sense to specify the type.
public abstract class Area implements Comparable<Area> {
#Override
public int compareTo(Area other) {
// ...
If I want to introduce another class to compare Area with, I thought I could do the following:
public abstract class Area implements Comparable<Area>, Comparable<Volume> {
#Override
public int compareTo(Area other) {
// ...
}
#Override
public int compareTo(Volume other) {
// ...
}
}
But the java compiler tells me:
Area.java:2: error: repeated interface
public abstract class Area implements Comparable<Area>, Comparable<Volume> {
^
Area.java:2: error: Comparable cannot be inherited with different arguments: <Area> and <Volume>
Are there any drawbacks specifying the type argument for the generic interface?
Why won't Java allow me this multiple implementation?
Note: I'm using Java version 1.7.0_45
No, it's not a drawback of specifying the generic - it's actually a feature. Also, I don't recall any drawback for using generics in interfaces, other than the well-known fact you can't instantiate a generic type nor create a generic array (but that's more a problem of implementation, not the interface itself).
It's due to type erasure. Comparable<Area> and Comparable<Volume> is essentially the same class for the VM, and, shortly after checking validity, also for compiler.
If you want to have two distinct comparable interfaces implemented, just use Comparators for them - it's generally easier to maintain composition than inheritance in classes.
For some applications (distinguishing generics at run-time) you may also try subclassing them, e.g. ComparableArea extends Comparable<Area> & ComparableVolume extends Comparable<Volume>, but that would, in this particular case, cause more trouble than it would solve IMO, since you'd still get Comparable cannot be inherited with different arguments error - but at least you could differentiate those interfaces by e.g. instanceof.
I think this way java is saying that related classes can be Comparable, but using artificial Comparator we can do more comparisons among unrelated classes.
So we should implement generic interface of related classes (classes within the same inheritance hierarchy). In case we want to add an artificial implementation, add an interface which can be passed through (so have pair of family of interfaces like Comparable and Comparator).
Related
Given an interface I:
interface I<T> {
public abstract T doSomthing(T other);
}
where any class C which implements the interface I will always use itself (C) as the type parameter:
class MyClass implements I<MyClass> {
#Override
public MyClass doSomthing(MyClass other) {
return null;
}
}
Is there a way to accomplish this without explicitly passing the class C as the parameter every time a new class implements the interface?
In other words is it possible, in an interface, to reference the class which implements that interface?
tl;dr
You asked:
Is there a way to accomplish this without explicitly passing the class C
No, not in Java.
Example
You seem to be describing exactly the scenario of the Comparable<T> interface bundled with Java. That interface has a single generic argument, for the type of the two objects to be compared. That interface requires a single method compareTo(T o) taking a single parameter of that same generic type.
Let’s look at an example usage in the OpenJDK source code, the source code for class Year.
The class declares itself explicitly as the type of comparison on the Comparable interface being implemented.
public final class Year
implements Temporal, TemporalAdjuster, Comparable<Year>, Serializable {
The compareTo method explicitly cites its own class as the type being compared.
#Override
public int compareTo(Year other) {
return year - other.year;
}
You asked:
Is there a way to accomplish this without explicitly passing the class C as the parameter every time a new class implements the interface?
It seems the answer is No. The implementing class must cite itself explicitly as the fulfillment of the generic type of the interface being implemented.
Caveat: (a) I am not an expert on such language matters. (b) I may have misunderstood your question.
To add to the other answer: what you're describing is a self type.
Some other languages have it (such as Scala).
But I'm afraid Kotlin doesn't. (Java doesn't, either.)
There has been long discussion about the possibility of adding it to a future version of Kotlin; it seems the potential uses may not be wide enough for it to be worthwhile, though there doesn't seem to be a final consensus.
The usual workaround is using a type parameter — similar to what C++ calls the curiously-recurring template pattern. It's not quite as typesafe in Java or Kotlin, as this question illustrates, but covers most of the same ground.
That's called self-bounded generics. It could be declared in Java as well as in Kotlin.
Java:
interface I<T extends I<T>> {
public abstract T doSomething(T other);
}
Kotlin:
interface I<T : I<T>> {
fun doSomething(other: T): T
}
But it doesn't mean, that generic parameter could be omitted then you declare classes, implementing this interface. It just imposes additional restrictions on type, you're passing as a generic parameter (narrowing it down to only one type). Type inference is not supported for class declaration neither in Kotlin, nor in Java.
Also see: Can I resolve a generic type from another generic declaration in an interface?
If you want to use sort() method from Arrays class you MUST implement Comparable interface. This is a really good idea - you can't sort objects if they're not compatible. So you can't sort if you can't compare it's references. In this case interface is used like compatibility checker.
The question is - how can I make:
a class with a method (may do something with 2 objects)
interface that checks if this 2 objects are comatible (have compatible references)
add to my class "must use this interface" rule, so you can't use this class method without implementing specific interface, just like Comparable class does ?
Example:
public class Employee implements Comparable<Employee> {
//fields
//setters, getters
// this method must be implemented to use Arrays.sort()
public int compareTo(Employee other) {
return Double.compare(salary, other.salary);
}
}
An interface can't check anything.
You can write this:
interface One { }
interface Two { }
SomeType someMethod(One one, Two two) { ... }
The compiler will not allow anybody's code to call someMethod(a, b) unless it can prove that a is an instance of some class that implements One and b is an instance of some class that implements Two.
Is that what you're asking?
Added Info:
Arrays.sort(Object[] a) is different: The compiler does not know whether the elements in the array implement the Comparable interface or not. That information is not available until run-time.
I don't know how java.util.Arrays.sort() does it, but you you want to do the same thing in your own code, you can write this:
interface One { }
interface Two { }
SomeType someMethod(Object oneAsObject, Object twoAsObject) {
One one = One.class.cast(oneAsObject);
Two two = Two.class.cast(twoAsObject);
...
}
This is different from my first example because the compiler will let you pass in any type of object, but the function will throw a ClassCastException at run time if the wrong type of object is passed.
But why would you want to wait until run time to find an error that you could have found at compile time? (e.g., why wait until the lander is descending toward the Martian surface to find a fatal flaw that you could have found before it was launched?)
Responding to your comment:
Yes, what I mean is: if you wan't to use sort() you must implement comparable. So the question is - can I determine, that you must use some X interface if you want to use my X method.
You could do this with an abstract class.
public interface MyInterface {
public void methodA();
}
public abstract class MyAbstractClass implements MyInterface {
public void methodB(
System.out.println("Pop");
)
}
Anything that wants to use methodB must extend MyAbstractClass, and therefore must implement MyInterface.
Suppose I am designing something like the following interface:
public interface MyInterface{
public MyInterface method1();
public void method2(MyInterface mi);
}
However, there is the caveat that the return type for method1 and the parameter for method2 match the concrete implementation and not just MyInterface. That is, if I have MyInterfaceImpl that implements MyInterface, it needs to have the following:
public class MyInterfaceImpl implements MyInterface{
#Override
public MyInterfaceImpl method1(){...}
#Override
public void method2(MyInterfaceImpl mi){...}
}
As written above, method1 won't cause any compile errors, but there is nothing guaranteeing that the return type matches in all implementations. Of course method2 won't even compile because the signature does not match the interface.
One candidate solution is to use self-referential or recursive bounds in generics:
public interface MyInterface<T extends MyInterface<T>>{
public T method1();
public void method2(T mi);
}
public class MyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
#Override
public MyInterfaceImpl method1();
#Override
public void method2(MyInterfaceImpl mi);
}
This would get me what I want with one exception: other implementations might pass the wrong generic type (nothing forces T to match the concrete type). So potentially someone else could implement the following:
public class NotMyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
#Override
public MyInterfaceImpl method1();
#Override
public void method2(MyInterfaceImpl mi);
}
That would compile just fine even though NotMyInterfaceImpl should implement MyInterface<NotMyInterfaceImpl>.* That makes me think I need something else.
*Note that I don't think I'm trying to violate LSP; I'm OK with the return type/parameter being subclasses of NotMyInterfaceImpl.
So I don't know of a clean way to do this. That leads me to believe that I might be focusing too much on implementation details in the interface, but it doesn't seem that way to me. Is there any way to do the type of thing I described, or is this some kind of smell that I'm putting something in an interface that doesn't belong there?
This is the exact situation faced by the Comparable interface (its compareTo method wants to take an argument the same type as the object it is called on). So what does it do? It's simply defined as Comparable<T>. The idea is that an implementing class "should" implement Comparable with itself as the parameter (allowing it to "compare to" itself); but this is not enforced (since there is no way to do it).
Yes, as you noted, this will allow any class to implement Comparable with a parameter of any other class: class Foo implements Comparable<Bar> where Foo and Bar have no relation to each other. However, this is not really a problem.
All the methods and classes (sorting, maximum, etc.) that require Comparable objects have the following generic type constraint <T extends Comparable<? super T>>. This ensures that objects of type T are comparable with themselves. That way, it is completely type-safe. So the enforcement is not made in the declaration of the Comparable interface, but in the places that use it.
(I notice that you use <T extends MyInterface<T>> while Comparable uses simply <T>. Although <T extends MyInterface<T>> will exclude cases where the type parameter does not implement MyInterface, it will not exclude cases where the type parameter does implement MyInterface, but is different than the class. So what's the point of half-excluding some cases? If you adopt Comparable's way of restricting it where they are used, it's type-safe anyway, so there is no point in adding more restrictions.)
I believe that this cannot be done. There is simply no way to refer to an object's implementation class in the framework of generics, nor, as far as i know, any way to construct a cage out of pure generics which is capable of constraining the implementation class to match a type parameter.
The most useful thing i can suggest is using a self-referential parameter, and then always acquiring instances of implementations from factory methods which look like:
public <T extends MyInterface<T>> T newInstance();
It is easier for a camel to pass through the eye of a needle than for an instance of NotMyInterfaceImpl to pass through that return type. So, although troublemakers could write classes which do not conform to your masterplan, they couldn't return them from factories. Unless NotMyInterfaceImpl extended MyInterfaceImpl; but then, in a sense, it would also be a MyInterfaceImpl, so perhaps that would be kosher?
EDIT: A slightly more useful version of that idea is to always pass instances of implementations of the interface around in a suitably restrictive holder, like:
class Holder<T extends MyInterface<T>> {
public final T value;
}
If someone gives you a Holder<Q>, then you know that Q must be a version of MyInterface bound to itself, which is what you're after.
The point of returning the interface is such that the method does not care the actual implementation of the returned object. In your case you actually want to mandate the type to be a particular sub-implementation of that interface.
To apply the constraints that you described above, IMHO the design should probably be a base class instead of an interface. This allows you to control the implementation, for example a top-level flow, and leave low-level strategy to sub-classes to implement:
class MyBaseImpl {
public final void fixedFlow() {
MyBaseImpl obj = method1();
obj.method2(this);
}
protected abstract MyBaseImpl method1();
....
}
There has to be other methods to make it interesting...; perhaps you have good reasons to want to do this...
Hope this helps!
What you are trying to do is not legal because you are trying to narrow the parameter of the implemented type, and this "does not make sense". You are tryint to use "covariant" parameters, and only covariant return types are allowed (and even logic, and only supported from Java 5).
I mean, if it was possible to use covariant parameter types, you could do things like:
MyInterface instance = new MyInterfaceImpl();
And then, invoke on "instance" the method with another implementation supported by the interface but not supported by the MyInterfaceImpl class this way:
instance.method2(new MyInterfaceImpl_2());
Java cannot convert MyInterfaceImpl_2 to MyInterfaceImpl, so it prevents you from doing so at compilation time.
What you could do is to widen the parameter, using "contravariant" parameter, which would be logic. For more detail on this, check this anser:
Demonstrate covariance and contravariance in Java?
The only workaround that I can think of, is to solve the problem at runtime, I mean, doing something like this:
public class MyInterfaceImpl implements MyInterface{
#Override
public void method2(MyInterface mi){
realMethod((MyInterfaceImpl) mi);
}
public void realMethod(MyInterfaceImpl) {...}
}
But you could get ClassCast exception, of course.
Is this what you are looking for?
public interface MyInterface {
static abstract class MyInterfaceImpl implements MyInterface {
#Override
public abstract MyInterfaceImpl method1();
#Override
public abstract void method2(MyInterfaceImpl mi);
}
MyInterfaceImpl method1();
void method2(MyInterfaceImpl mi);
}
And you could even implement method 1 or 2 instead of making them abstract.
I've created two Java interfaces, Tree<T> and BinarySearchTree<T extends Comparable<T>>, where the second interface extends the first one. I have an implementation of BinarySearchTree, called LinkedBinarySearchTree. The following code obviously complains at compile-time:
Tree<Object> a = new LinkedBinarySearchTree<Object>();
since LinkedBinarySearchTree implements an interface that has specified T as a Comparable type, and Objects are not Comparable. I understand this perfectly and it does not constitute a problem with my implementations.
What I'm looking to understand is whether this approach might be dangerous in practice. I cannot envision a scenario where the "narrowing down" of the data type from Tree to BinarySearchTree would give me a runtime error (ClassCastException, perhaps?) but I was looking to confirm this with more knowledgeable people. In essence, is "narrowing down" the type held by an interface when extending that interface considered bad practice and, if so, why?
Quite the opposite in fact - it is actually good practice.
Remember that using generics is a technique to avoid coding mistakes by catching as many mistakes as possible at compile time. By tightening the specificity of your BinarSearchTree interface you are actually making it more difficult for people to misuse it accidentally. Not only that but their mistakes will be discovered at compile time.
It does not seem bad practice at all. Whether you get a ClassCastException depends on what you try to do, not on the implementation approach.
A common case of the "narrowing down" is when one wants to specialize the types of certain implementations, deriving from a common base. For example, to implement some calculator, with a different return type each time:
public interface Calculator<T> {
public Number calculate(T... arguments);
}
public interface NumberCalculator<T extends Number> extends Calculator<T> {
#Override
public T calculate(T... arguments);
}
public interface IntegerNumberCalculator extends NumberCalculator<Integer> {
#Override
public Integer calculate(Integer... arguments);
}
public interface FloatNumberCalculator extends NumberCalculator<Float> {
#Override
public Float calculate(Float... arguments);
}
The arguments above may be specified to be something different to <T>, while the return type can continue to be set to <T> for every subclass, thereby offering much better type consistency compared to having to return a Number object all the time.
I'm trying to write a generic class in Java. A few methods in that class require that T extends Comparable<T>. How can I make it such that T is required to be comparable only if one of those methods is used? Or maybe there's some other way I should organize my class?
Here's the class I'm trying to implement. Its and array that I plan to use on both comparable and non-comparable types.
// I know Java has its own containers, but this
// is homework and I'm not allowed to use them
class Array<T>
{
// Some methods that pose no
// special restrictions on T
// These require that T be comparable
public Array<T> union(...) {...}
public Array<T> intersect(...) {...}
}
You can hide type T for method. T of Test is not the same as T of CompareMethodhere.
public static class Test<T> {
<T extends Comparable<T>> void compareMethod(T t, Class<T> classt) {
}
void normalMethod(T t) {
}
}
Now example
Test<String> test = new Test<String>();//Comparable class
test.compareMethod("",String.class);//works fine
Test<Random> tes1t = new Test<Random>();//Non Comparable class
tes1t.compareMethod(new Random(),Random.class);//Compilation error here
tes1t.normalMethod(new Random());//Works fine
new Test<Random>().compareMethod("",String.class);// Not a good but can be valid
new Test<String>().compareMethod(new Random(),Random.class);//Compilation error here
Update:
After being cursed about this solution I did some search in java API and this practice gets followed for toArray() method
ArrayList<String> string = new ArrayList<String>();
string.toArray(new Integer[5]);<--Illegal however <T> is hide by toArray method
Edit: It looks like this is possible after all (see AmitD's post). But anyway, other possible solutions are
Refactor the methods requiring comparable into a subclass
Just use casts in the relevant methods, meaning that that part will only be checked at runtime.
It wont be possible through normal method such as using comparable.
It would be better if you share what is the exact requirement.
If Sorting in ArrayList/Arrays are your goal, then Comparing Non Comparable classes is useless. Sorting can only be done in objects of the same or sub types.
But if you are going to use compare for checking if the objects are equal or not then I'll suggest that you override equals(Object O) method.