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.
Related
I'm facing this error while work with Java generics, and I don't understand which is the problem;
I have two classes like these:
public abstract class BaseClass{
....
}
public class OneClass extends BaseClass{
....
}
I have a generic repo for OneClass:
public class MyRepo<T extends BaseClass>{
List<T> getElements();
}
Then I have a method that should works whit generics:
private MyRepo<OneClass> myRepo;
public <T extends BaseClass> List<T> myMethod(){
return myRepo.getElements();
}
The method doesn't work unless I force a cast to List ( as shown below ):
public <T extends BaseClass> List<T> myMethod(){
return (List<T>) myRepo.getElements();
}
I don't understand which is the problem given that OneClass extends BaseClass.
Thanks for any suggestion.
Having a method of the form:
<T> T myMethod()
makes the inference of the actual T dependent on the call-site:
String s = myMethod();
Integer i = myMethod();
Considering your scenario one could invoke your method like this:
List<BaseClass> a = myMethod();
List<OneClass> a = myMethod();
As you can see this can be incorrect as myMethod could actually return another subtype of BaseClass (lets say TwoClass) which is not correct to cast to List<OneClass> - thus you need the unsafe cast to List<T>.
You should change the signature of myMethod to one of the following:
public List<? extends BaseClass> myMethod(){}
public List<BaseClass> myMethod(){}
The first variant states that this is a list of any subtype of BaseClass the other just omits that information.
Dependent on what you want to achieve check the other answer or read about PECS (Producer Extends, Consumer Super) or f-bounded polymorphism / self-types to return the concrete type.
Error message tells you that not every T extends BaseClass is OneClass
You should make sure that the field myRepo is the same type as T as in your method. If you force it to be OneClass you cant use othere types except OneClass. So there is no use of a generic. If you want to allow every extending class from BaseClass you could make the class of the mehtod generic in oder to use the same type of T as shown below:
public class FunctionClass<T extends BaseClass> {
private MyRepo<T> myRepo;
public List<T> myMethod(){
return myRepo.getElements();
}
}
I have interface:
interface Identifable<T extends Serializable> {
T getID();
}
and class that implement this:
public class Cat implements Identifable<Long> {
public Long getID(){...};
}
everything works fine. so far. Now I want to create GenericDAO, why I cannot create this?:
public abstract GenericDAO<T extends Identifable<S>> {
T getByID(S id);
}
I can only declare my GenericDAO as this:
public abstract GenericDAO<T extends Identifable, S> {
T getById(S id);
}
And complete class:
public CatDAO extends GenericDAO<Cat, Long> {
Cat getById(Long id);
}
But i think it's useless, because I repeat information. I already declared, that Cat implements Identifable< Long >, so why do I must declare GenericDAO< Cat, Long >, not just GenericDAO< Cat > ?
In Java, every generic type must be specified. You can go without specifying any type, but you can't go without specifying just one.
Also, every generic type must be specified in the declaration. If you want to have class GenericDAO<T extends Identifable<U>>, you must add the generic type declaration for U to your class declaration like this (since U is actually a generic type here):
public abstract class GenericDAO<T extends Identifable<U>, U>
The following is partially off-topic, but you might find it useful.
I've noticed that in your definition of GenericDAO two generic types are not tied to each other. This might not be what you want.
What you have here is a particular case in which the two generics are matching (the Long type in the Cat and CatDAO definitions). Consider having these declarations:
public class Dog implements Identifable<Long>
public class DogDAO extends GenericDao<Dog, String>
This would force you to write the getById method in DogDAO method:
Dog getById(String id);
Your getId method in the Dog returns a Long so your getById method int DogDAO would have to compare Strings to Longs. This is valid thing to do, but it's a bit counter-intuitive. Having a getById method for DogDAO that takes a Long parameter makes more sense, since the Dogs IDs are actually Longs.
If you want to tie the two types together, you can define the GenericDAO class as:
public abstract class GenericDAO<T extends Identifable<S>, S>
You still have to specify the second parameter, but at least the compiler can help you make sure that the types are matching.
Try this:
public abstract class GenericDAO<S extends Serializable, T extends Identifable<S>> {
abstract T getByID(S id);
}
Given the following type signatures, I'm able to compile and run the code under Maven with both JDK 6 and JDK 7, but Eclipse gives a "Bound mismatch: The type F is not a valid substitute for the bounded parameter <F extends Field<TP,F>> of the type Field<TP,F>" error in TupleVisitor.
I believe I need these types, although I understand this is difficult to motivate given the stripped-down example. Can anyone suggest a workaround that will let me continue to work in Eclipse?
public abstract class Tuple<F extends Field<TP, F>, TP extends Tuple<F, TP>>
public class VariableTuple<F extends Field<VariableTuple<F>, F>> extends Tuple<F, VariableTuple<F>>
public class ConstantTuple<F extends Field<ConstantTuple<F>, F>> extends Tuple<F, ConstantTuple<F>>
public class Field<TP extends Tuple<F, TP>, F extends Field<TP, F>>
public class ConstantField extends Field<ConstantTuple<ConstantField>, ConstantField>
public class VariableField extends Field<VariableTuple<VariableField>, VariableField>
public interface TupleVisitor {
public <F extends Field<VariableTuple<F>, F>> void visit(VariableTuple<F> tuple, F field); //Eclipse error
public <F extends Field<ConstantTuple<F>, F>> void visit(ConstantTuple<F> tuple, F field); //Eclipse error
}
Filed bug at: https://bugs.eclipse.org/bugs/show_bug.cgi?id=422503
No simple workaround identified. While Rohit Jain's answer wouldn't work with a visitor pattern, I took his follow-up advice and removed F as a type parameter from Field.
This seems to a be a bug with eclipse, as it is compiling fine under javac for me too. In fact, there are few bugs related to self-referential Java generics related to eclipse that I found, but this isn't there. So, may be you should file one.
As for a workaround of this, I just found one, which I doubt you would like, as you have to make your interface generic. Yes, you heard it right. Declaring the type parameters with the interface itself, makes the code compile fine. Here's the compiling code:
interface TupleVisitor<E extends Field<VariableTuple<E>, E>,
F extends Field<ConstantTuple<F>, F>> {
void visit(VariableTuple<E> tuple, E field);
void visit(ConstantTuple<F> tuple, F field);
}
Of course there are two type variables, as the bounds on both of them are different. Check if this suits your need, because this really sounds to be as weird work-around, as the number of type parameters depends on the total number of implementors of Tuple class (Actually weird, isn't it?). Or else you have to do some other changes.
The problem likely is that type parameters are provided by the caller. Given your declarations, somebody could declare
class ReallyConstantField extends ConstantField {}
and then invoke TupleVisitor.visit while providing ReallyConstantField for F. The visit method's type constraint would then read
ReallyConstantField extends Field<ConstantTuple<ReallyConstantField>, ReallyConstantField>
so we use a ConstantTuple<ReallyConstantField>. The type constraint for that class would then read
ReallyConstantField extends Field<ConstantTuple<ReallyConstantField>, ReallyConstantField>
which is incorrect, as ReallyConstantField is a ConstantField which is a Field<ConstantTuple<ConstantField>, ConstantField>, which is an inconvertible type.
That is, even though you declare a type parameter with an extends bound, the only valid type argument is a single type. That is, you don't need a type parameter at all, but could simply declare:
void visit(ConstantTuple<ConstantField> tuple, ConstantField field);
Update
BTW, if these are supposed to be, as the example suggests, parallel class hierarchies with a one-to-one correspondence between the classes of different hierarchies, there is a simpler way to write the generics:
abstract class Tuple<F extends Field<TP, F>, TP extends Tuple<F, TP>> {}
class VariableTuple extends Tuple<VariableField, VariableTuple> {}
class ConstantTuple extends Tuple<ConstantField, ConstantTuple> {}
class Field<TP extends Tuple<F, TP>, F extends Field<TP, F>> {}
class ConstantField extends Field<ConstantTuple, ConstantField> {}
class VariableField extends Field<VariableTuple, VariableField> {}
interface TupleVisitor {
public void visit(VariableTuple tuple, VariableField field);
public void visit(ConstantTuple tuple, ConstantField field);
}
I have the following sets of classes:
public abstract class GSObject<T extends GSObject<T>> {
public abstract boolean matches(String toMatch);
//Other functions
public static <T extends GSObject<T>> T findMatch(List<T> objects, String toMatch){
//Code that iterates through the list, seeing if one matches;
}
}
public abstract class Phrase extends GSObject<Phrase> {
//More code
}
public class Request extends Phrase{
#Override
public boolean matches(String toMatch){
//Implementation of matches()
}
}
Running the following command: Request.findMatch(allRequests,chat); gives the following error:
Bound mismatch: The generic method findMatch(List<T>, String) of type GSObject<T> is not applicable for the arguments (List<Request>, String). The inferred type Request is not a valid substitute for the bounded parameter <T extends GSObject<T>>
If I do Phrase.findMatch(allPhrases, chat); it does not throw an error, meaning that this has to do with double inheritance. Do I have to write another static function that works with a Class that extends a Class that extends GSObject?
I've looked into making GSObject an interface, but it has some classes that I would like to define (not abstractly) in the class.
Is there something I am missing (in any of the three classes), or do I need to create an interface that defines the function matches() (What I am trying to avoid)?
One option is to make Phrase generic in the same way that GSObject is:
public abstract class Phrase<T extends Phrase> extends GSObject<T> {
public class Request extends Phrase<Request> {
This way, Request extends GSObject<Request> (unlike in your code, where Request extends GSObject<Phrase>).
Another option might be to decouple some of these dependent types by using wildcards, e.g. by one of these:
public static <T extends GSObject<T>> T findMatch(List<? extends T> objects, String toMatch){
public static <U extends GSObject<?>> U findMatch(List<U> objects, String toMatch){
though this can be tricky to get right. Note that with this approach, Request will still advertise that it can handle any List<? extends Phrase>, so you lose some of the benefit of the static type system. (In other words, these versions make your classes more permissive than they're really supposed to be.)
A third option is to do both of the above. It does make sense, after all, for Request.findMatch to take a List<? extends Request>.
Without seeing more of your code, it's hard to know which of these makes most sense for your case.
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.