I have a class defined as follows:
public class MultiFacilitySearchDataProvider <T extends Facility & MilepostValue & Copyable<T>>
The class has this method:
protected T getFacility(final FacilityInstance instance) {
final MultiFacilitySearchDAO dao = new MultiFacilitySearchDAO(instance);
ENM.execute(dao);
return dao.getResultModel(); // Compile error here
}
The DAO method called above looks like this:
public MultiFacilitySearchModel getResultModel() {
return resultModel;
}
And MultiFacilitySearchModel is defined as follows:
public class MultiFacilitySearchModel implements Copyable<MultiFacilitySearchModel>, Facility,
Serializable, MilepostValue, MenuDisplayValues
The problem is that the line return dao.getResultModel() generates a compile error "Type mismatch: cannot convert from MultiFacilitySearchModel to T". I don't understand why I'm getting this error, since MultiFacilitySearchModel implements the three interfaces specified for the generic type T. What am I missing?
You can specify any class that meets the prequesites as type parameter. Therefore T need not be a supertype of MultiFacilitySearchModel. That means however, that
return dao.getResultModel()
may not return an object of a type that extends T. Java doesn't allow you to do this.
The method MultiFacilitySearchDAO.getResultModel() has no generic type and will allways return MultiFacilitySearchModel instead of T.
Although MultiFacilitySearchModel can be used as T in some class that extends MultiFacilitySearchDataProvider.
In your class MultiFacilitySearchDAO you have the method
public MultiFacilitySearchModel getResultModel()
which is obviously returning an instance of MultiFacilitySearchModel. There is nothing generic here. The return type is fix.
Your class MultiFacilitySearchDataProvider on the other hand declares the method
protected T getFacility(final FacilityInstance instance)
The type variable T is constrained to implement the three interfaces Facility & MilepostValue & Copyable. This is much less then being a MultiFacilitySearchModel.
I could easily create a class
public MyFacilitySearchModel implements Copyable<MyFacilitySearchModel>, Facility, MilepostValue
and then use a
MultiFacilitySearchDataProvider<MyFacilitySearchModel>
The result type of getResultModel() would still be MultiFacilitySearchModel which can't be casted to MyFacilitySearchModel.
Maybe you DAO class should also be generic. Or declare the method as
protected MultiFacilitySearchModel getFacility(final FacilityInstance instance)
Related
There is an interface with a method that returns a Class, like so.
public interface MyInterface {
public Class<? extends Object> returnsSomething ();
}
I have to create a class which implements the interface, like so.
public class MyClass implements MyInterface {
public Class<? extends Object> returnsSomething () {
return Object; // This is currently an error.
}
}
The return line in the implementation of returnsSomething in MyClass is incorrect. The IDE hints "cannot find symbol Object".
What correction do I need to apply in returnSomething's body to compile successfully?
Object is just the name of the class.
Object.class is the instance of the Class<Object> class that represents the Object class. See Class.
So you need:
return Object.class;
Your return type is incorrect in your method. You need to understand that this '.class' is used in Java for code Reflection. Generally you can gather meta data for your class such as the full qualified class name, list of constants, list of public fields,etc... So in your example you are basically saying that the Class type to be returned for the wildcard used will either be Object or Subclass of object to be returned at Runtime. Note that you want Java to determine the object returned at Runtime.
Is there anyway to get a generic type in a class constructor in order to pass it to a parent constructor?
Given base class:
public class BaseSupport<T>{
private Class<T> type;
public BaseSupport(Class<T> type){
this.type = type;
}
}
Is there anyway to create a subclass to do this?
public class Support<T> extends BaseSupport<T> {
public Support() {
// is there anyway to know what "T" is here?
super( T.class );
}
}
And then finally, I would simply be able to create a class like:
public class MyClass extends Support<OtherClass>{
// no need to explicitly define a constructor here since the Support class handles it
}
I know Guava has TypeToken to help with retrieve generic type information, but given that super() must be the first method called in a constructor, I can't use it to extract the type information to pass to the parent class.
I suspect that this isn't feasible, but thought I would ask to see if there are any features/tricks that I don't know about in Java 7 since 'T' would be available at compile time.
Did you see the option mentioned in the TypeToken docs?
Capture a generic type with a (usually anonymous) subclass and resolve it against a context class that knows what the type parameters are. For example:
abstract class IKnowMyType<T> {
TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
new IKnowMyType<String>() {}.type => String
You could effectively do this.
public class MyClass extends Support<OtherClass>{
// no need to explicitly define a constructor here since the Support class handles it
public MyClass() {
super(OtherClass.class);
}
}
And in support, have a constructor that accept a Class type and call the super keyword as I have done above (eliminating T.class all together).
Update: Alternatively, you can use Reflection to get ParameterizedType on your BaseSupport class and not need to provide an argument to your BaseSupport public constructor.
Resource:
Reflecting Generics.
Related Answer on StackOverflow.
I've got problem in my code in Java. I have four(important) Classes:
public class RDOutput extends OutputType
public class RDAnalysis extends AnalysisProperties
Now I'm trying to make a method in Analysis properties:
public abstract void display(ArrayList<? extends OutputType> results);
The main problem list, the objects in the ArrayList will be different subtypes of OutputType. In my class RDAnalysis I try to make specific overriding:
public void display(ArrayList<RDOutput> results) {
but eclipse says: Name clash: The method display(ArrayList) of type RDAnalysis has the same erasure as display(ArrayList? extends OutputType) of type AnalysisProperties but does not override it
I'm not familiar with Java tricks, I tried searching in documentation and I didn't find any solution to this problem.
My question is: Is that trick that I'm doing (Basic type in abstract and Extended in final function) possible in Java (if yes, how can I do that?) or do I have to make some enum to solve this?
I suggest you to introduce generic parameter to your class and use it to parametrize your method:
public abstract class A<T extends OutputType> {
public abstract void display(ArrayList<T> results);
}
public class B extends A<RDOutput> {
public void display(ArrayList<RDOutput> results) {}
}
It's because your display doesn't cover every case of the abstract method. Maybe try something like this :
public class RDOutput extends OutputType {}
public class OutputType {}
public abstract class AnalysisProperties<T extends OutputType> {
public abstract void display(ArrayList<T> results);
}
public class RDAnalysis extends AnalysisProperties<RDOutput> {
#Override
public void display(final ArrayList<RDOutput> results) {
}
}
The problem is that you try to override a method while restricting possible parameters.
=> ArrayList<? extends OutputType> accepts more possible elements than ArrayList<RDOutput> since RDOutput extends OutputType.
You break the rule that says: the concerned subclass method has to encompass at least elements of superclass one and NEVER restrict them.
So compiler avoid to valid this override.
By the way, avoid to type your reference with concrete values like ArrayList.
What about a LinkedList passed as arguments? ... prefer a more generic relevant type like List.
Problem here is that, after type erasure comes into play, the signature of the two methods are undistinguishable: they have the same return type and they can both accept a ArrayList<RDOutput> but the first one (the generic one) can also accept any ArrayList<T extends OutputType>.
This mean that, although the JVM won't be able to choose which one to call at runtime if you pass an ArrayList<RDOutput>, at the same time your display method does not override the abstract one because your method only work for lists of RDOutput, so if you pass a List<T extends OutputType> with T != RDOutput your specific implementation doesn't accept it.
You should consider using a type parameter on the whole class as suggested in other answers, or accept the fact that you won't be able to use any RDOutput specific methods in your display method without a cast.
if a method is expecting ArrayList<? extends OutputType>
ArrayList<RDOutput> cannot be passed to it, as parent type allows any child class of OutputType in arraylist.
consider a code like this
AnalysisProperties properties = new RDAnalysis();
properties.display(arraylist consisting of any child class of OutputType); //this line will cause runtime problems
There's the following class:
public class LivingBeing { … }
Then there's
public class Human extends LivingBeing { … }
Now there's also this wrapper:
public class LivingBeingWrapper<T extends LivingBeing> { … }
And to complete the picture there's also the method
public boolean validate(LivingBeingWrapper<LivingBeing> livingBeingWrapper)
Now when writing the following code
LivingBeingWrapper<Human> wrapper = createHumanWrapper();
validate(wrapper);
I get the following compile error:
The method validate(LivingBeingWrappe<LivingBeing>
livingBeingWrapper) in the type MyType is not applicable for the
arguments (LivingBeingWrapper<Human>).
But why? Human extends LivingBeing.
A banana is-a fruit. But a list of bananas is not a list of fruit. Otherwise you could take a list of bananas and add an apple (given that an apple is-a fruit).
That sounds rather gnomic, but it's key to what's happening above. You need to specify your wrapper such that it takes types extending LivingBeing.
For further info, see this article, and in particular the "Generics are not Covariant" section.
Your validate method declares that it must be called with a LivingBeingWrapper parameterised with LivingBeing. However, you're passing in a LivingBeingWrapper parameterised with Human. Try changing your method declaration from this:
public boolean validate(LivingBeingWrapper<LivingBeing> livingBeingWrapper)
to this:
public boolean validate(LivingBeingWrapper<? extends LivingBeing> livingBeingWrapper)
Change your below method: -
public boolean validate(LivingBeingWrapper<LivingBeing> livingBeingWrapper)
to
public boolean validate(LivingBeingWrapper<T> livingBeingWrapper)
Since this method is inside your class which is like: -
public class LivingBeingWrapper<T extends LivingBeing>
So, you can use the type T in your method parameter, and T will be replaced by Horse.. For your particular reference..
And if your method takes some different type than the one in class definition (T), then you can use this declaration: -
public boolean validate(LivingBeingWrapper<? extends LivingBeing>
livingBeingWrapper)
Now, if you have to call validate(LivingBeingWrapper<Human>), your method has to be defined to take generic type parameter type Human, which extends LivingBeing, which is what your T type is (As it also extends LivingBeing in your class definition)
I've a simple generic class follows which accepts a generic type parameter, which is the same as the one declared as a type parameter of the class:
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
public abstract class SimpleClass<T extends AnnotatedElement>
{
public void operate()
{
Method m = null;
this.doSomething(m); // Error : SimpleClass.java:[34,10] doSomething(T) in SimpleClass<T> cannot be applied to (java.lang.reflect.Method)
}
protected abstract void doSomething(T annotatedElement);
}
This code fails to compile at the following line:
this.doSomething(m);
with this error:
Error : SimpleClass.java:[34,10] doSomething(T) in SimpleClass<T> cannot be applied to (java.lang.reflect.Method)
Am I missing something here? The type parameter T is marked as T extends AnnotatedElement. As such, I would expect the call to doSomething with a java.lang.reflect.Method argument to compile successfully.
Method implements AnnotatedElement, but that doesn't require that T is a method. What if the class is declared as SimpleClass<Constructor>? That satisfies <T extends AnnotatedElement>, but doesn't support conversion from Method.
There's no way to know that T is a Method. It could just as well be e.g. a Package, and then your operate() wouldn't make sense, trying to pass a Method to something expecting Package
This is because T doesn't matter here. All you know is that the type is AnnotatedElement.
The following change would make it compile:
protected abstract void doSomething(AnnotatedElement annotatedElement);
Your generic method is not implemented correctly. Change your generic method to
protected abstract<T extends AnnotatedElement> void doSomething(T annotatedElement);
Above statement creates correct generic method. This will remove compilation error.