I have an interface for a variety of classes, all of which should implement Iterator, so I have something like
public interface A extends Iterable<A> { ...otherMethods()... }
For the concrete classes, however, this means I must use
public class B implements A { public Iterator<A> iterator() {...} }
when I'd prefer (or at least, think I'd prefer) to use public Iterator<B> iterator() {...} so that concrete use of the class could have the explicit type (in case I wanted methods that weren't in the interface to be available, or some such. Maybe that should never come up? Or it's poor design if it does?
The flipside is that using the Iterator interface
public interface A extends Iterator<A> { ...otherMethods()... }
the concrete classes compile just fine with
public class B implements A { public B next() {...} }
What gives?
Carl was right, my first answer didn't compile but this seems to. Not sure if it's what you want exactly.
public interface A<T extends A> extends Iterable<T> {
}
public class B implements A<B> {
#Override
public Iterator<B> iterator() {
return null;
}
The concrete class compiles fine because B extends A, and since Java 5 a return type on a subclass can be a subclass of the return type on the superclass.
As for the generic, I have hit the same wall, and you have two options that I know of.
One is to paramaterize A:
public interface A<T extends A> extends Iterable<T>
then:
public class B implements A<B>
However, that has a disadvantage that you will need to give a parameter of A, instead of having it fixed, even if you want A:
private class NoOneSees implements A<A>
As to the question of if you actually want Iterator<B>, in the case of an Iterable, most likely that is preferable, and considering that these are interfaces, the need to redeclare the parameter is probably reasonable. It gets a little more complicated if you start inheriting concrete classes, and for things that have meaning other than an Iterable, where you may want covariance. For example:
public interface Blah<T> {
void blah(T param);
}
public class Super implements Blah<Super> {
public void blah(Super param) {}
}
public class Sub extends Super {
public void blah(Super param) {}
//Here you have to go with Super because Super is not paramaterized
//to allow a Sub here and still be overriding the method.
}
Similarly for covariance, you can't declare a variable of type Iterator<A> and then assign an Iterator<B> in it, even if B extends A.
The other option is live with the fact that further implementation/subclasses will still reference A.
The other answers have the right gist - but you'll get the right mechanics by declaring the generic type as
A<T extends A<T>>
This forces a class to return an iterator that is of its own type or lower - so you would be able to declare
class B implements A<B>
but not
class B implements A<A>
which I suspect is closer to what you want (i.e. implementations must return iterators over themselves, rather than simply over As).
Note that your experiences with Iterator vs Iterable stem from the lack of covariance of generic types; an instance of B is an A, but an Iterator<B> is not an Iterator<A>.
I guess this is what you want:
public interface A<T extends A<?>> extends Iterable<T>
public class B implements A<B> {
public Iterator<B> iterator() {...}
}
Your design decisions are your own, but I can't think of any reason for EVERY class in a design to implement Iterable. There must be some kind of thing that is contained in a collection but isn't actually a collection itself. I would take a long hard look at the fundamental design. Maybe some iterables will want to return iterators of things that are not related to themselves.
Related
I'm new to the F-Bounded interface concept.
I have a F-Bounded interface, A. I want to use it in the interface B. I only want to use generics on A, but if I don't use generics, B will throw warnings.
I'm looking for the best practice in this case. It would be nice to show also the implementation of B with the best solution.
public interface A<T extends A<T>>{
T getSomething();
void setSomething(T);
}
Here is the one i would like to use, but it obviously throws warnings.
public interface B{
A getA();
void setA();
}
This one works just fine, as long as they are few interfaces. As soon as I add more interfaces which i.e. using B, things get totally messy.
public interface B<T extends A<T>>{
T getA();
void setA(T);
}
Also, should I use the implementation of A in the interface B? This would eliminate the recurring generics, but it doesn't feel right.
Simply use an unbounded wildcard.
public interface B{
A<?> getA();
void setA(A<?> a);
}
I have a very specific problem with java generics. The follwowing classes and interfaces have been predefined:
public interface IFirst<R, T> {...}
public abstract class AbstractFirst<T extends AbstractFirst, L extends IFirst<String, T>> {...}
public interface ISecond extends IFirst<String, AbstractSecond> {...}
public abstract class AbstractSecond extends AbstractFirst<AbstractSecond, ISecond> {...}
Now I've created a following repo definition which seems to be valid:
public abstract class AbstractRepo<T extends AbstractFirst<T, IFirst<String,T>>> {...}
But now that i want to extend it:
public class RepoFirst extends AbstractRepo<AbstractSecond> {...}
I get the following error:
Bound mismatch: The type AbstractSecond is not a valid substitute for the bounded parameter
<T extends AbstractFirst<T,IFirst<String,T>>> of the type AbstractRepo<T>
I cannot change the first four (at least not radically) beacuse they are too heavily ingrained with the rest of the application, but the second two are new and up for change if need be.
Also intrestingly it allows the following (with raw type warnings):
public class RepoFirst extends AbstractRepo {
...
#Override
AbstractFirst someAbstractMethod() {
return new AbstractSecond() {...};
}
...
}
But for code clarity I would like to implement it with clearly defining AbstractSecond as the generic type for Abstract Repo.
What am I missing?
Your AbstractRepo expects an instance of IFirst and not a subtype of IFirst. But your AbstractSecond is clearly not IFirst. (I mean it is, from a OO standpoint but for generics, List<Number> is not the same as List<Integer>). It's ISecond. It might work if you could change your AbstractRepo from IFirst to ? extends IFirst as you did for AbstractFirst.
I know it is possible to wildcard with multiple types in case of methods and classes but what about variables? E.g. can I require an ArrayList to only take elements that implement both of two different interfaces that are not in the same type hierarchy? See code below for what I am trying to do.
import java.util.ArrayList;
interface A {}
interface B{}
interface AB extends A, B{}
class D <T extends A & B> { //This works but this is a class
T variable;
}
public class C {
ArrayList<AB> myList1 = new ArrayList<AB>(); // compiles
ArrayList<? extends AB> myList3 = new ArrayList<AB>(); //compiles
//The following does not compile.
ArrayList<? extends A & B> myList4 = new ArrayList<AB>();
//This works but this is a method:
public static <T extends A & B> T someMethod(ArrayList<? extends T> list) {
return null;
}
}
Yes:
class C<T extends A & B> {
ArrayList<T> field;
public <T2 extends A & B> void method() {
ArrayList<T2> localVar;
}
}
It looks a bit odd that you have to define an alias for the generic "type" outside of the scope where you use it but it works. I find it's easiest to see with the method: T2 is never used in the method declaration. It's solely used inside of the method.
It's unfortunate that these inner type limits become part of the public API this way but that's the only way I know to make this work.
If you don't want this, then try an inner, private interface (AB) in your example.
Java does not support multiple inheritance of classes - a class can extend only one single class (although a class can implement multiple interfaces). Hence I believe the
ArrayList<? extends A & B>
doesn't work.
Solution would be create a super type that extends both A & B and then pass the type to your method. Something like
inteface C extends A,B{}
ArrayList<? extends C>
This is an existing interface:
public interface MyInterface<T, U> {
public T foo(U u);
}
I want to implement this interface under the assumption that T and U are the same type. I thought maybe I could leave the type parameters in as they are, and then as long as I only ever instantiate this particular implementation with two of the same type, that it might work:
public class MyOuterClass<A> {
public class MyClass<T, U> implements MyInterface<T, U> {
#Override
public T foo(U u) {
return u; //error here
}
//even though in the only instantiation of MyClass, T and U are the same
private MyClass<A, A> myInstance = new MyClass<A, A>();
}
But, perhaps unsurprisingly, this doesn't work, as types T and U are incompatible.
So then I thought maybe I could change MyClass to specify that its types would always be the same, by changing it to something like MyClass<A, A> implements MyInterface<A, A> or similar, but I get errors saying that T is already defined.
Is there a way to implement MyClass so that its two types will be the same?
(I'm more of a C++ guy than Java, so sorry if I'm missing something fundamental about Java's generic's here.)
Your myclass needs to look like this:
public class MyClass<T> implements MyInterface<T, T> {
#Override
public T foo(T in) {
return in;
}
}
Let's review what your suggested class definition does:
public class MyClass<T, U> implements MyInterface<T, U>
In this code, T and U do two things each:
in the first occurance they define a type variable of your MyClass class
in the second occurance they specify the concrete type of the MyInterface class
Since inside the body of your class T and U are unbounded type variables (i.e. nothing is known about the actual types), they are assumed to be incompatible.
By having only a single type variable in your MyClass you make your assumption explicit: there's only a single type, and I'm using it for both types of the interface.
Last but not least: remember that the compilation of a type is complete once the source is fully handled. In other words: contrary to what C++ does, "instantiation" of a generic type ("template type" or similar in C++; Sorry for my rusty terminology) does not handle. MyClass<Foo> and MyClass<Bar> are the same type, as far as the JVM is concerned (only the compiler actually distinguishes them).
Define a single type parameter for MyClass:
class MyOuterClass<A> {
public class MyClass<T> implements MyInterface<T, T> {
public T foo(T u) {
return u;
}
}
// Need only one 'A' here.
private MyClass<A> myInstance = new MyClass<A>();
}
When you say
public class MyClass<T> implements MyInterface<T, T> {
... you are defining one generic variable for MyClass and you are saying that it fulfills both the roles T and U in MyInterface.
Suppose that I have the following class:
public class Either<A, B> {
public Object get();
}
Either is a type that stores one object of either type A or B. get() retrieves that one object.
The question is whether or not it is possible to use generics to alter the method signature of get() so that the type returned is not just Object, but any common supertype of A and B. For example, an Either<Integer, Long> can have get() return Number, an Either<Deque<T>, Set<T>> can have get() return Iterable<T> or Collection<T>, and so on. (Obviously, an Either<Foo,Foo> should have get() return Foo).
If this is at all possible, if I had Either<List<A>, List<B>>, what is the most specific type get() can return? Is it raw List, wildcard List<?>, or something else entirely?
Java inference do have something similar, we can do
public static <C, A extends C, B extends C> C get(Either<A,B> e)
{ return (C)e.get(); }
inference:
A=Integer, B=Long ==> C=Number
A=List<Integer>, B=List<Long> ==> C=List<? extends Number>
usage:
Either<Integer, Long> x = ...;
get(x); // the return type is Number
However there's probably no way to turn it into an instance method. We would need to write
public class Either<A,B>
public <C super A|B> C get() { ... }
or simply
public A|B get(){ ... }
which is not supported in Java
Why not define an abstract class C, containing as much logic common to A and B as you deem necessary, and refer to that in your Either class:
public class Either<C> {
public C get();
}
That doesn't seem like much of an answer, but since Java erases your type information anyway when compiling (that it to say, your compiled code sees only Object instead of an A or a B), then you are in the best position to define what should be retained in an explicit common class.
As far as I know, it is not possible: your Either<A,B> class makes an assumption about a generic third type (let's call it C), which both A and B would extend: while it is possible to write something like public class Either<A extends MyNonFinalClass, B extends MyNonFinalClass> {}, Java doesn't allow forward-referencing a generic type, so you cannot even write something like Either<A extends C, B extends C, C>. Clearly a shame, as your Either class would really be handy :)
You need to make sure A and B share a common ancestry.
public class Either<A extends CommonAncestor, B extends CommonAncestor> {
public CommonAncestor get() {....}
}
or
public class Either<C, A extends C, B extends C> {
public C get() {....}
}