Given the following code :
public abstract class Participant {
private String fullName;
public Participant(String newFullName) {
this.fullName = new String(newFullName);
}
// some more code
}
public class Player extends Participant implements Comparable <Player> {
private int scoredGoals;
public Player(String newFullName, int scored) {
super(newFullName);
this.scoredGoals = scored;
}
public int compareTo (Player otherPlayer) {
Integer _scoredGoals = new Integer(this.scoredGoals);
return _scoredGoals.compareTo(otherPlayer.getPlayerGoals());
}
// more irrelevant code
}
public class Goalkeeper extends Player implements Comparable <Goalkeeper> {
private int missedGoals;
public Goalkeeper(String newFullName) {
super(newFullName,0);
missedGoals = 0;
}
public int compareTo (Goalkeeper otherGoalkeeper) {
Integer _missedGoals = new Integer(this.missedGoals);
return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
}
// more code
}
The problem is that Goalkeeper won't complie.
When I try to compile that code the Eclipse throws:
The interface Comparable cannot be implemented more than once with
different arguments: Comparable<Player> and Comparable<Goalkeeper>
I'm not trying to compare with Player, but with Goalkeeper, and only with him.
What am I doing wrong ?
The problem is described in Angelika Langer's Generics FAQ #401:
Can a class implement different instantiations of the same generic
interface?
No, a type must not directly or indirectly derive from
two different instantiations of the same generic interface.
The reason
for this restriction is the translation by type erasure. After type
erasure the different instantiations of the same generic interface
collapse to the same raw type. At runtime there is no distinction
between the different instantiations any longer.
(I highly recommend checking out the whole description of the problem: it's more interesting than what I've quoted.)
In order to work around this restriction, you can try the following:
public class Player<E extends Player> extends Participant implements Comparable<E> {
// ...
public int compareTo(E otherPlayer) {
Integer _scoredGoals = this.scoredGoals;
return _scoredGoals.compareTo(otherPlayer.getPlayerGoals());
}
// ...
}
public class Goalkeeper extends Player<Goalkeeper> {
// ...
#Override
public int compareTo(Goalkeeper otherGoalkeeper) {
Integer _missedGoals = this.missedGoals;
return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
}
// ...
}
As far as the logic of your design goes, you are not doing anything wrong. However, Java has a limitation that prevents you from implementing the same generic interface with different type parameters, which is due to the way it implements generics (through type erasure).
In your code, Goalkeeper inherits from Player its implementation of Comparable <Player>, and tries to add a Comparable <Goalkeeper> of its own; this is not allowed.
The simplest way to address this limitation is to override Comparable <Player> in the Goalkeeper, cast the player passed in to Goalkeeper, and compare it to this goalkeeper.
Edit
public int compareTo (Player otherPlayer) {
Goalkeeper otherGoalkeeper = (Goalkeeper)otherPlayer;
Integer _missedGoals = new Integer(this.missedGoals);
return _missedGoals.compareTo(otherGoalkeeper.getMissedGoals());
}
I would like to add two points to the existing good answers.
There are reasons why you might not want the design you tried even if it had been possible. It is a bit fluffy.
There are other possible solutions in addition to the one that Sergey Kalinichenko presents.
Your design has downsides
As you know, your design isn’t possible with Java. It’s a restriction with Java generics. Let’s for a moment play what if it had been possible. It would imply some behaviour that I think many would find surprising and/or confusing.
With you design, assume we have:
Goalkeeper goalkeeper1 = new Goalkeeper("Imene");
Goalkeeper goalkeeper2 = new Goalkeeper("Sofia");
Player goalkeeper3 = new Goalkeeper("Maryam");
goalkeeper1.compareTo(goalkeeper2); // would call Goalkeeper.compareTo(Goalkeeper)
goalkeeper1.compareTo(goalkeeper3); // would call Player.compareTo(Player)
We can take it one step further:
List<? extends Player> list1 = new ArrayList<Goalkeeper>();
List<? extends Player> list2 = new ArrayList<Player>();
Now we fill both lists with goalkeepers (only) and sort them. Now list1 should be sorted using Goalkeeper.compsreTo() and list2 probably using Player.compareTo(). It’s beginning to be confusing, isn’t it? Would you want such a design? Would you prefer one where you are more explicit about which way to compare is used when? (Yes, I know, you cannot fill the lists through the variables list1 and list2. You would have to fill the lists before assigning them to those two variables.)
A couple of solutions
Solution 1: Instead of one of your compareTo methods (or both of them) use a Comparator. Either a Comparator<Player> or a Comparator<Goalkeeper> or one of each. For example:
Comparator<Player> playerComparator = Comparator.comparingInt(Player::getScoredGoals);
Solution 2: Introduce a separate class for players that are not goalkeepers. I am calling it FieldPlayer for now for lack of a better word. Both FieldPlayer and Goalkeeper should be subclasses of Player. FieldPlayer implements Comparable<FieldPlayer> and Goalkeeper already implements Comparable<Goalkeeper>. Now Player doesn’t need to implement Comparable, and the conflict is avoided.
Related
While working on a project, I came across the following code segment which appears to provide code, entirely contained inside a new variable declaration, which appears to override a method. I've, come across code of this form before but admittedly, I do not fully understand it. If anyone could explain the programming mechanisms upon which this code is based, I'd be very truly grateful. Particularly, when are overridden methods of this sort permitted inside of variable declarations. What other sorts of data structures allow such behavior? When is it advantageous to write code of such nature? Why not override the method outside of a variable declaration?
tempRequests.sort(new Comparator<Integer>()
{
#Override
public int compare(Integer integer1, Integer integer2)
{
return integer1.compareTo(integer2);
}
});
What other sorts of data structures allow such behavior?
-> You can sort objects by implements interface Comparable.
For example:
public class Car implements Comparable<Car> {
private String name;
#Override
public int compareTo(Car b) {
return name.compareTo(b.name);
}
}
->You can also use Comparator without override method compare inside the inner class.
public class Car implements Comparator<Car> {
private String name;
private double price;
#Override
public int compare(Car b1, Car b2) {
return b1.price - b2.price;
}
}
When is it advantageous to write code of such nature? Why not override the method outside of a variable declaration?
-> Image that after use sort object Car by name, you want to sort by something else (like by price, by weight).How to do this when you want to sort objects in different ways at different times? We use Comparator with define inside the inner class to do this.
*Additionally, Comparator is a functional interface since an only abstract method to implement. You can rewrite using a funky syntax in one line of code:
Ex:
Compareator<Car> byPrice = (b1,b2) -> b1.price - b2.price;
This mechanism has been explained well in the comments.
As an aside: ever since Java 8, this usage of anonymous classes is considered somewhat old fashioned, as it can be replaced with a simple Lambda expression:
tempRequests.sort((l, r) -> l.compareTo(r));
This applies to all "Functional Interfaces", which is defined as an interface with exactly one non-static and non-default method.
Can I require classes implementing an interface to have a certain static field or method and access/invoke that field or method through a generic type argument?
I have an interface, Arithmetical<T>, which specifies several functions like T plus(T o) and T times(T o). I have as well a Vector<N extends Arithmetical<N>> class, which is intended for vectors (of variable dimension) with components of type N. I ran into an issue, however, when trying to implement the dot product.
I want to implement the method N dot(Vector<N> o). For this, I plan to start with whatever N's zero is and iterate through both Vector<N>s' List<N>s, adding the product of each pair of elements to my total. Is there a way to specify in Arithmetical<T> that all implementing classes must have a static (and preferably final) field ZERO and start dot(Vector<N> o)'s body with something along the lines of N sum = N.ZERO;?
If not, what other approaches might there be to this problem? I want to allow 0-dimensional vectors, so I can't just begin by multiplying the vectors' first components. Is there a way to instantiate an object of a generic type, so I can merely specify a T zero() method in Arithmetical<T>?
I have a reason for not using Java's numerical types—I want to have vectors with complex components.
Here's Arithmetical:
public interface Arithmetical<T> {
public T plus(T o);
public T minus(T o);
public T negate();
public T times(T o);
public T over(T o);
public T inverse();
// Can I put a line here that requires class Complex (below) to define ZERO?
}
Vector:
public class Vector<N extends Arithmetical<N>> {
private List<N> components;
public Vector<N>(List<N> cs) {
this.components = new ArrayList<N>(cs);
}
public N dot(Vector<N> o) {
// Here's where I need help.
}
}
And Complex:
public class Complex implements Arithmetical<Complex> {
public static final Complex ZERO = new Complex(0, 0); // Can I access this value through N if <N extends Arithmetical<N>>?
private double real;
private double imag;
public Complex(double r, double i) {
this.real = r;
this.imag = i;
}
/* Implementation of Arithmetical<Complex> (and some more stuff) not shown... */
}
I'm quite new to Java (and programming in general); I will likely not understand complex (ha) explanations and workarounds.
Thanks!
(Python is a suggested tag... Huh.)
You need a "zero" for every possible implementation type. A constant in the interface won't do, because a constant cannot be overridden and must remain the same.
The solution is to add a new method to your Arithmetical interface:
public T zero();
Each implementation is forced to implement this and return its own version of zero. In this case, you're using it as a starting point for adding; it's the additive identity.
The Complex class implementation would look like this.
#Override
public Complex zero() {
return ZERO;
}
If your instances are mutable, then don't use a constant; just return new Complex(0, 0).
Another idea is to borrow from what Streams do when reduce-ing items and combining them to one single item -- take an identity value that represents the initial state, i.e. no items collected yet -- zero.
public N dot(Vector<N> o, N identity) {
N dotProduct = identity;
// Perform operations on each item in your collection
// to accumulate and return a dot product.
}
The caller will have to supply the identity value.
Complex dotProduct = vectorOfComplex.dotProduct(otherVector, new Complex(0, 0));
Can I put a line here that requires class Complex (below) to define ZERO?
No. The best you can do is to define an interface, for example:
interface ZeroProvider<A extends Arithmetical<A>> {
A zero();
}
and then supply a compatible instance of that where you need to provide a zero, for example:
class ComplexZeroProvider implements ZeroProvider<Complex> {
public Complex zero() { return new Complex(0, 0); }
}
There's something you can do sometimes using reflection in situations like this. If you put the following method in the Vector class, it will invoke a static method N.zero() (with caveats, below):
protected N zero() {
try {
Type s = getClass().getGenericSuperclass();
#SuppressWarnings("unchecked")
Class<N> n = (Class<N>) ((ParameterizedType) s).getActualTypeArguments()[0];
Method zero = n.getMethod("zero");
return n.cast(zero.invoke(null));
} catch (RuntimeException | ReflectiveOperationException x) {
// probably better to make a custom exception type
throw new IllegalArgumentException("illegal type argument", x);
}
}
However, it's important to understand what this is actually doing. This is getting the type argument from the class file of the direct superclass of this. In other words, there must actually be a superclass of this with an actual type argument (which is a class).
The usual idiom then is that you'd create all of your vectors like this:
new Vector<Complex>() {}
instead of this:
new Vector<Complex>()
Or you'd declare subclasses like this:
public class Vector<N> {
// ...
public static class OfComplex extends Vector<Complex> {
}
}
Since you need an actual superclass with a type argument which is a class, instantiations like in the following examples will fail:
new Vector<Complex>()
new Vector() // never use this anyway
new Vector() {} // never use this anyway
// also, you can't do stuff like this:
public Vector<T> copy() {
return new Vector<T>(this) {};
}
In your case I think the suggestions in the other answers are better, but I wanted to post this answer along with the proper explanation and caveats which are sometimes not included. There are cases where this technique is actually good, mainly when you have pretty tight restrictions on how the class in question is extended. Guava TypeToken will also do some of the reflection for you.
Also, this is the best Java can do at doing exactly what you're asking for (at the moment), so it's worthwhile to point out just as a comparison.
I've seen a few questions about the sort for collections having errors in Java. The error I am showing is this:
The method sort(List<T>) in the type Collections is not applicable for the arguments (ArrayList<Time>)
I have imported java.util.Collections and ArrayList. I also imported the class I am calling from. Here is my code:
In the class being called from:
private ArrayList<Time> times;
...
public ArrayList<Time> getTimes() {
return this.times;
}
In the class I am calling the array list to:
public class TimeTUI {
private Scanner scan;
private TimeManager timeManager;
...
private ArrayList<Time> getSortedTimes() {
ArrayList<Time> sortedTimes = this.timeManager.getTimes();
Collections.sort(sortedTimes);
return sortedTimes;
}
The error is appearing on the line showing:
Collections.sort(sortedTimes);
The class Time has to be a Comparable.
Collections.sort(List) expects that the class T implements Comparable interface. If you have used many of the inbuilt classes, you wouldn't find problem, but for the custom classes sort doesn't know how to sort them. So, by implementing Comparable interface, you give definition to a method compareTo.
public class Time implements Comparable {
public int compareTo(Object o) {
// provide your logic of how to sort Time objects.
}
}
Your class type in the List or ArrayList must implement the Interface comparable and override properly the compareTo(...) method,
Is you break this contract and dont implement the interface. the Class Collections has not a valid criteria/rule to compare/sort your list, and therefore your compiler will complain...
I don't think that it is the ArrayList that is the issue here. For example:
ArrayList<String> names = new ArrayList<>();
...
Collections.sort(names);
works just fine.
The content of the list must be comparable so that the sort can work. In this case the Time class and any sub-type must implement Comparable.
I have been trying to create a comparator through a field of an object, and I can't seem to be able to morph the comparator's type to what I want.
I'm trying to do something like this:
public class Sort {
private ArrayList list;
public Class<?> type;
private Object obj = "Continent";
Sort(ArrayList list, String type) throws ClassNotFoundException
{
this.list = list;
this.type = Class.forName(type);
}
Comparator a = new Comparator<this.type>(){
#Override
public int compare(b.area o1, b.area o2) {
// TODO Auto-generated method stub
return 0;
}
};
is it possible or would I need to write out the methods for each individual class case?
Part I
is it possible [...]?
Not the way you're trying it. You're confusing compile time and run time, i.e.:
Generics are a pure compile time concept in Java. In fact, the generic type is removed during compilation (that's called type erasure). It only exists to give you type safety before compilation, meaning while writing your code.
But the instance type is only assigned at run time. And because you don't know its type during compile time, you had to use a wildcard generic for it. So you only know the type, when you're executing your code.
So you can see that you can't use the information you gathered while executing your code to help you write it.
I highly recommend you read Oracle's tutorial on generics.
Part II
would I need to write out the methods for each individual class case?
I'm with Paul on this. I'm sure we can help you but you should give us an idea of what you're trying to accomplish.
...
Based on on your comment, I think the following would be a good solution.
Your model of the reality consists of continents, countries and cities. Hence you should have classes Continent, Country and City. Since you're modeling population, all of them should have a method getPopulation(). And this is one thing they have in common; all of those things are populated. The way to address this common structure / behavior in Java is to create an interface (let's call it Populated) with a method getPopulation() and have all of those classes implement it:
public interface Populated {
int getPopulation();
}
public class Country implements Populated {
#Override
public int getPopulation() {
...
}
}
// same for Continent and City
Now you have three classes but they can all be treated as one thing, as being populated. For example you can collect them in a list:
List<Populated> populated = new ArrayList<>();
populated.add(new Country());
populated.add(new City());
...
And this list can be sorted with a comparator which works for instances of Populated:
public class PopulationComparator implements Comparator<Populated> {
public int compare(Populated left, Populated right) {
return left.getPopulation() - right.getPopultion();
}
}
I'm having trouble understanding why the following doesn't work and I'm sure the answer is related to something basic I am not understanding and hope someone can help.
I understand about using interfaces in an ArrayList such that if I have:
public interface Weapon { ... }
public class Gun implements Weapon { ...}
public class Knife implements Weapon { ... }
you can then insert anything that implements Weapon into the an array of weapons:
ArrayList<Weapon> weapons = new ArrayList<Weapon>();
weapons.add(new Gun());
weapons.add(new Knife();
I get that, but what is confusing me is the understanding of why ArrayList<Gun> isn't compatible with ArrayList<Weapon> in other ways. To illustrate, the following is legal:
public void interfaceIsTheArgument(Weapon w) { ... }
...
interfaceIsTheArgument(new Gun());
interfaceIsTheArgument(new Knife());
but the following is not:
public void interfaceIsTheArgument(ArrayList<Weapon> w) { ... }
...
interfaceIsTheArgument(new ArrayList<Gun>());
interfaceIsTheArgument(new ArrayList<Knife>());
because the last function call reports that the method isn't applicable for its arguments.
My question is why if the method knows it tasks an ArrayList with an interface as the generic type, why isn't it okay to pass in an array list of knives in that last statement?
To "fix" the code, you need to use a generic bound:
public void interfaceIsTheArgument(List<? extends Weapon> w) { ... }
...
interfaceIsTheArgument(new ArrayList<? extends Weapon> ());
interfaceIsTheArgument(new ArrayList<Knife>());
The key reason is List<Gun> is not a subclass of List<Weapon>. The reason for this fact can be illustrated by this code:
List<Gun> guns = new ArrayList<Gun>();
// If List<Weapon> was a super type of List<Gun>, this next line would be allowed
List<Weapon> weapons = guns; // Won't compile, but let's assume it did
weapons.add(new Knife()); // Compiles, because Knife is a Weapon
Gun gun = guns.get(0); // Oops! guns.get(0) is a Knife, not a Gun!
By using the bound <? extends Weapon>, we are saying we'll accept any generic type that is a subclass of Weapon. Using bounds can be very powerful. This kind of bound is an upper bound - we are specifying the top-level class as being Weapon.
There's also a lower bound, that uses this syntax:
List<? super Weapon> // accept any type that is a Weapon or higher in the class hierarchy
So, when to use each one? Remember this word PECS: "Producer extends, consumer super". This means on the producer side of the code (where the objects are created) use extends, and on the consumer side of the code (where the objects are used) us super. Once you try it a few times, you'll understand through experience why it works well.
This SO question/answer covers it well.
This is one of the most asked questions about generics. It a List<Gun> was a List<Weapon>, you could do
List<Gun> gunList = new ArrayList<Gun>();
List<Weapon> weaponList = gunList;
weaponList.add(new Knife());
gunList.get(0).fire(); // ClassCastException
This would thus break the type-safety promised by generics.