In Java, one can allow an interface-specified function to return a Comparable simply by using a return type of Comparable. This isn't particularly useful, however, since there's no guarantee that two different implementations of this interface will return Comparables that can be compared to each other. Is there some way of doing this?
To illustrate my question, let's say we're making a class that stores objects and automatically 1) groups them and 2) sorts these groups. So something like:
GroupList.java
public class GroupList<T extends Groupable> {
private HashMap<Comparable, T[]> data;
public void add(T e) {
Comparable group = e.getGroup();
if(!data.containsKey(group)) { /* make new group for the element */ }
/* add element to matching group */
}
public T[][] get() {
/* return all the data, with the sets ordered by their Comparable */
}
}
Groupable.java
public interface Groupable {
public Comparable getGroup();
}
This runs into the aforementioned problem, however, which means that things like this are possible:
Class A implements Groupable {
String datestamp;
public Comparable getGroup() { return datestamp; }
}
Class B implements Groupable {
Date datestamp;
public Comparable getGroup() { return datestamp; }
}
This is further complicated by the fact that while all the Comparables must work with each other, I do not know ahead of time what they will be.
You could make the Comparable subclass a generic parameter, too.
Something like
public interface Groupable<G extends Comparable<G>> {
public G getGroup();
}
public class GroupList<G extends Comparable<G>> {
private HashMap<G, Groupable<G>[]> data;
public void add(Groupable<G> e) {
G group = e.getGroup();
if(!data.containsKey(group)) { /* make new group for the element */ }
/* add element to matching group */
}
public Groupable<G>[][] get() {
/* return all the data, with the sets ordered by their Comparable */
}
}
In this case, if you have class A implements Groupable<String>, and class B implements Groupable<Date>, you can't mix them in the same GroupList, but you can still mix a different class with the same grouping class, e.g. class C implements Groupable<String>
GroupList<String> groupList = new GroupList<String>();
groupList.add(new A()); //ok
groupList.add(new B()); //compile error
groupList.add(new C()); //ok
Related
public interface Iterator<T> {
// Returns true if the iterator is valid (points to an element), false otherwise.
boolean isValid();
// Returns the current element and moves forward. This method can only be called if the iterator is valid. If the iterator points to the last element, it becomes invalid after the call.
T next();
// Returns the current element and moves backwards. This method can only be called if the iterator is valid. If the iterator points to the first element, it becomes invalid after the call.
T prev();
}
In a class that does not implement interface Iterator, how is it possible to create a method that returns Iterator<K>, when you can only create methods for an interface inside a class that implements it?
public class ABC<K> implements EFG<K>{
public Iterator<K> minIt() {
//method body
//return Iterator<K> variable
}
}
The class ABC containing the method minIt() does not implement Iterator<T>
(No classes implement the interface Iterator <T> )
You can use an Anonymous Class that implements the interface:
For instance:
interface Foo<T> {
T foo();
}
class Bar<T> {
T t;
public Foo<T> bar() {
return new Foo<T>() { // <-- Anonymous class implementing `Foo`
public T foo() {
return t;
}
};
}
}
Execution:
Bar<String> b = new Bar<>();
b.t = "hello"; // with a setter in real life
Foo<String> f = b.bar();
f.foo(); // will return "hello"
The other option which I think would be the most common is to use a method that returns the interface, for instance the list interface has an iterator() method even though it itself doesn't implements the Iterator interface.
List<String> list = new ArrayList<>();
Iterator<String> stringIterator = list.iterator();
Here's the implementation
Simple. By making a class that implements it. Note that you have a type that you came up with on your own and you named it Iterator. Given that java.util.Iterator exists, this is a really bad idea. You should pick another name.
public class ABC<K> implements EFG<K> {
// Let's say this contains the items that can be iterated over.
private List<K> list = new ArrayList<K>();
class MyIterator implements my.pkg.Iterator<K> {
private int position = 0;
#Override public boolean isValid() {
return position > -1 && position < list.size();
}
#Override public K next() {
if (!isValid()) throw new NoSuchElementException();
return list.get(position++);
}
#Override public K prev() {
if (!isValid()) throw new NoSuchElementException();
return list.get(position--);
}
}
public Iterator<K> minIt() {
return new MyIterator<K>();
}
}
Note that classes that you put in classes can only be constructed in instance contexts within that class: They have a 'secret' field of your outer's type. Hence why the code in MyIterator can access the list field of your outer class.
Java has 'anonymous inner class literal' syntax which lets you shorten this: Instead of explicitly declaring class MyIterator, you can also write:
public Iterator<K> minIt() {
return new your.pkg.Iterator<K>() {
private int position = 0;
#Override public boolean isValid() {
// same code goes here as the previous snippet
}
};
}
This anonymous inner class form is a lot more common. It's just syntax sugar - a shorter way to write the same thing.
I've interface MyInterface and two classes ( Summary, Detail) are implementing this, and overriding compareTo.
A third class DetailMe is extending Detail
Another class (MyApi) is using List<MyInterface> , and complaining for Collections.sort , what am i doing wrong ?
public class Summmary implements MyInterface, Comparable<Summary> {
private Detail detail;
public Summary(Detail detail) {
this.detail = detail;
}
// properties
// methods
#Override
public int compareTo(Summary o) {
// Do work
}
}
==
public class Detail implements MyInterface, Comparable<Detail> {
// properties
// methods
#Override
public int compareTo(Detail o) {
// Do Detail work
}
}
==
public class DetailMe extends Detail {
// Do work
}
==
public class MyApi {
private List<MyInterface> myList;
public MyApi(List<MyInterface> myList) {
this.myList = myList
Collections.sort(this.myList); // COMPLIATION ERROR
}
}
You need to ensure (in a way the compiler knows of) that the list only contains one type of object, because your objects can't compare with each other.
So, your list must be either a List<Summmary> or a List<Detail>.
That is, unless you define the ordering of mixed elements, but then both classes would have to implement public int compareTo(MyInterface o).
I have some base class that implements iterable
public class EntityCollection implements Iterable<Entity> {
protected List<Entity> entities;
public EntityCollection() {
entities = new ArrayList<Entity>();
}
public Iterator<Entity> iterator() {
return entities.iterator();
}
... etc
This is subclassed.
public class HeroCollection extends EntityCollection {
public void doSomeThing() { ... }
I would like to do the following:
HeroCollection theParty = new HeroCollection();
theParty.add(heroA);
theParty.add(heroB);
for (Hero hero : theParty){
hero.heroSpecificMethod();
}
But this fails at compile time, because the iterator is returning entities, not heroes. I am looking for some way to restrict the list such that it can contain only the types of the subclass, so that I can call methods which are specific to the subclass on the result of the iterator. I know it must use generics somehow but I can't seem to figure out how exactly to structure it.
I would suggest making EntityCollection generic.
public class EntityCollection<T extends Entity> implements Iterable<T> {
protected List<T> entities;
public EntityCollection() {
entities = new ArrayList<T>();
}
public Iterator<T> iterator() {
return entities.iterator();
}
... etc
public class HeroCollection extends EntityCollection<Hero> {
...
}
Then, HeroCollection's iterator method will return an Iterator<Hero>
(Also note: the way you're designing your collections (with separate methods for specific types of collections) suggests that your code may be poorly designed. However, if so, that's a separate problem.)
i have one class implemeting two different interfaces ,example:
public interface SortList{
void Sort();
search();
delete();
}
public interface unSortedList{
search();
delete();
}
class List implements ordenedList,unordenedList{}
I wanted to switch between ordened interface or not ordened list,thank you for your help.
You have to make 2 different class like OrderedList and UnorderedList. Implements are just a guarantee you have implemented those mehtots. So you have to make a switch case or if else in your methods or you have to make two different class.
I don't know what meaning you put behind "Ordened" and "UnOrdened", and if it makes sens to have a class implementing both, but anyway, here is an example on how you can use multiple implementations of interfaces, trying to keep up with your stuff.
I suppose by ordered the Java meaning as explained here, which is not sorted.
Let's say an Ordered interface gives the possibility to access some object (of type T) by index and to search or find for a given object:
public interface Ordered<T> {
T getNth(int i);
T find(T o);
}
Let's say an UnOrdered interface provides only the way to find an object:
public interface UnOrdered<T> {
T find(T o);
}
Now we can defined a class that implements both interfaces:
public class MyList<T> implements Ordered<T>, UnOrdered<T> {
List<T> theList;
public MyList(T...a) {
theList = Arrays.asList(a);
}
// The list of objects are neither sorted nor hashed.
// Only way to find an object is to iterate through the list
public T find(T o) {
for (T e : theList) {
if (e.equals(o)) {
return e;
}
}
return null;
}
public T getNth(int i) {
return theList.get(i);
}
}
public static void main(String[] args) {
MyList<Integer> mylist = new MyList<>(2,8,6,1,7,3,5,9,10,4);
System.out.println(mylist.getNth(3));
// => print 1
System.out.println(mylist.find(3));
// => print 3
System.out.println(mylist.find(42));
// => print null
}
You could have done a better job in describing the problem and what you are trying to solve for, assuming that I understood the problem, you can achieve this with Java 8 Default methods here is how
public interface UrdenedList{
void ordenate();
default T search(){
// default implementation here
}
default void delete(){
// default implementation here
}
}
public interface UnordenedList{
default T search(){
// default implementation here
}
default void delete(){
// default implementation here
}
}
I wanted to switch between ordened interface or not ordened list,thank
you for your help.
class List implements OrdenedList,UnordenedList{
void ordenate(){
// implementation here
}
T search(){
if(condition)
return OrdenedList.search();
else
return UnordenedList.search();
}
}
void delete(){
if(condition)
OrdenedList.delete();
else
UnordenedList.delete();
}
}
Notice Resolving conflicts by Explicitly choosing to call methods from interfaces OrdenedList, and OrdenedList
I have a (generic) class that holds meta data for other classes. The meta data is used in several ways (writing and reading XML data, database, output as text, etc). So far this works. But I have come across a problem when using all of this for classes that inherited from other classes.
Please have a look at the following code (I have tried to produce a minimal example that is compilabe except the line marked below):
class A {
public Meta<? extends A> getMeta() {
return new Meta<A>();
}
public void output() {
/*
* Error shown in eclipse for the next line:
* The method output(capture#1-of ? extends A) in the type
* Outputter<capture#1-of ? extends A> is not applicable for the arguments
* (A)
*/
getMeta().getOutputter().output(this);
}
}
class B extends A {
#Override
public Meta<? extends B> getMeta() {
return new Meta<B>();
}
}
class Meta<CLS> {
public Outputter<CLS> getOutputter() {
return null;
}
}
class Outputter<CLS> {
public void output(CLS obj) {
}
}
I can change A.getMeta() to return Meta<A> to make above line compilabe, but then I cannot override it as Meta<B> getMeta() in class B.
Any ideas on how to solve this?
What if you do this? It requires one more class, but it seems it is going to work:
class T{
//put common methods here, generic methods are not common, so they will not be here
}
class A extends T{
public Meta<A> getMeta() {
return new Meta<A>();
}
public void output() {
/*
* Error shown in eclipse for the next line:
* The method output(capture#1-of ? extends A) in the type
* Outputter<capture#1-of ? extends A> is not applicable for the arguments
* (A)
*/
getMeta().getOutputter().output(this);
}
}
class B extends T {
public Meta<B> getMeta() {
return new Meta<B>();
}
}
class Meta<CLS> {
public Outputter<CLS> getOutputter() {
return null;
}
}
class Outputter<CLS> {
public void output(CLS obj) {
}
}
if you do not want to create another method you can use composite. There are many good discussions about compositions over inheritance.
Everything will be the same except A and B classes:
class A{
public Meta<A> getMeta() {
return new Meta<A>();
}
...
}
class B {
private class A a;
public Meta<B> getMeta() {
return new Meta<B>();
}
//use a here if you need, a is composed into B
}
The reason you cannot override public Meta<A> getMeta() with public Meta<B> getMeta() is that instances of B will be castable to A, and such a casted instance would need to return a Meta<A>. While it may be that a Meta<B> can serve as a Meta<A>, the compiler doesn't know that.
Imagine instead that you are returning List<A> and a List<B>. It is allowable to put instances of A and B into a List<B>, but it is not allowable to put instances of B into a List<A>, so the List<B> that is actually being returned by B can not serve as a List<A>.
Changing List<A> to List<? extends A> allows the code to compile, because List<B> is technically a subclass of List<? extends A>, but it will not allow you to do everything you may expect.
B b = new B();
A casted = (A)b;
casted.getList().add(new A());
The compiler will accept the first and second line without issue, but it will take issue with the third:
The method add(capture#1-of ? extends A) in the type List<capture#1-of ? extends A> is not applicable for the arguments (A)
If you investigate a bit, you'll find that this casted variable will accept neither elements of A nor B. The compiler has remembered that the object was casted and may not actually be able to accept anything that extends A.
I'm trying to hunt down documentation for this behavior, but I'm failing. Eclipse tooltips are suggesting that I should give it an element of type null, which is obviously nonsense. I'll update if I find anything on it.
EDIT: The behavior described is a product of "Capture Conversion" as described here. Capture Conversion allows wildcards to be more useful by changing the bounds of type arguments over the course of assignments and casts. What happens in our code is simply that the bounds are constricted to the null type.
I will answer this myself since I found a working solution.
Although this solution is not type-safe, it works and requires the least changes to my existing codebase. If anyone comes up with something that works and doesn't require the #SuppressWarnings, I will accept that answer.
class A {
Meta<?> getMeta() {
return new Meta<A>();
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public void output() {
Outputter out = getMeta().getOutputter();
out.output(this);
}
}
class B extends A {
#Override
public Meta<?> getMeta() {
return new Meta<B>();
}
}
class Meta<CLS> {
public Outputter<CLS> getOutputter() {
return null;
}
}
class Outputter<CLS> {
public void output(CLS obj) {
}
}