Example:
class AbstractConverter <T> {
public abstract T convert(AbstractEntity e);
}
class CityEntity extends AbstractEntity {...}
class CityConverter extends AbstractConverter {
#Override
public CityDTO convert(CityEntity entity) {...} // why can't I do that??
}
As my CityEntity is of type AbstractEntity, why can't I do that in my cityConverter?
The method convert(CityEntity) of type CityConverter must override or implement a supertype method
I guess the solution is to cast, but it's not ellegant:
#Override
public CityDTO convert(AbstractEntity entity) {
CityEntity cityEntity = (CityEntity) entity;
}
You can't reduce the allowed parameter type, because you would break Liskov substitution principle. If one calls convert on an unknown AbstractConverter implementation (due to polymorphy), (s)he would guess that he can always pass any AbstractEntity implementation. This wouldn't be the case if CityConverter only allows a very specific subtype.
Now about your code:
class AbstractConverter <T> {
public abstract T convert(AbstractEntity e);
}
The first thing that wonders me here is: why is AbstractEntity a fixed type here? I would name the converter class AbstractEntityConverter or something like this if I always want to convert AbstractEntity instances into something different.
So I guess you really want something like this:
class AbstractConverter<F, T> {
public abstract T convert(F source);
}
Where F is the "from" type which acts as the source and T is the target type, which will be returned. So you can let the AbstractConverter subtypes decide what they likes to convert.
Then you have this:
class CityConverter extends AbstractConverter {
}
Why do you use AbstractConverter as a raw type here? Shouldn't it be?
class CityConverter extends AbstractConverter<CityDTO> {
}
But anyway, if you like to use my suggestion, then also add the source type:
class CityConverter extends AbstractConverter<CityEntity, CityDTO> {
#Override
public CityDTO convert(CityEntity entity) {...}
}
This would work.
Your CityConverter extends AbstractConverter and AbstractConverter<T> requires implementation for
public abstract T convert(AbstractEntity e);
It is not a problem that extends AbstractConverter uses raw-types because overridden method can be more specific in case of returned object (since it is still of type described by parent class).
But problem appears when in derived class you want to require more specific type as argument.
Remember that derived class can still be used from reference which is of one of parents type like it is possible to have code like:
AbstractConverter ac = new CityConverter();
So when we will invoke ac.convert(...) compiler will allow us to use any type of AbstractEntity as argument, not only CityEntity which could brake code of CityConverter#convert.
Which is why we can't declare more specific type of method argument when overriding it.
Now about question from your title:
Why do I need cast in this case?
...
CityEntity cityEntity = (CityEntity) entity;
you need casting because entity is declared to be AbstractEntity which means there is a chance that passed instance may not be of type CityEntity so compiler can't compile code like:
CityEntity cityEntity = entity;//error without cast
By casting you are basically saying "I am sure that passed instance will be of type (CityEntity) and if not, I am willing to face consequences and am ready to see my application stopped by ClassCastException".
Related
Given
public class Foo {
public static class FooBuilder { ... }
}
I want to write a method on a third class that returns Foo, given Foo.FooBuilder.class
i.e.
Foo f = x.make(Foo.FooBuilder.class, someData);
Is it possible to declare a signature using generics that can imply the return type? Is there some language feature that lets me say "type U is outer class of type T"?
Obviously, it is possible to specify that type extends, or is the base of, a generic type (U extends T or U super T, respectively) but I am looking for U outer T which is, I think, more than Java can offer, even indirectly, at least in 1.7, which I am targeting.
So far, I have simply declared both inner and outer types, which works but is a wider definition than I am after and looks clumsy too.
public <TYPE,BUILDER> TYPE make(Class<BUILDER> builderClass, Map<String,Object> data) {
// Construct TYPE
}
Is there a way to infer TYPE without explicitly providing a template parameter?
There is a Class#getDeclaringClass method that may work in your case.
Quoting the docs:
If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared.
EDIT:
After the clarification of OP, here is the new suggestion:
You create an generic interface to mark all your nested classes:
public interface Nested<P> {
}
Then you apply it to your Foo.Bar class like this:
public class Foo {
public static class Bar implements Nested<Foo> {
}
}
Then in your factory you can have the following:
public <P> P make(Class<? extends Nested<P>> clazz, Map<String, Object> someData) {
// do whatever you need to do
return (P) clazz.getDeclaringClass();
}
However, with this construct, there is not way to validate it your nested class is the real class, declared when implementing the generic interface.
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)
Sorry for the title, couldn't come up with anything clearer.
I have the following structure:
public interface Vehicle {...}
public class Car implements Vehicle {...}
then:
public abstract class Fixer {
...
abstract void fix(Vehicle vehicle);
...
}
and would like to have:
public class CarFixer extends Fixer {
void fix(Car car) {...}
}
but this doesn't work. Eclipse says: The type CarFixer must implement the inherited abstract method Fixer.fix(Vehicle). Any idea how can I solve this?
You can use Generics to solve this:
public abstract class Fixer<T extends Vehicle> {
abstract void fix(T vehicle);
}
public class CarFixer extends Fixer<Car> {
void fix(Car car) {...}
}
The problem with your original version is that the fix method allows any type of vehicle, but your implementing class allows only cars. Consider this code:
Fixer fixer = new CarFixer();
fixer.fix(new Bike()); // <-- boom, `ClassCastException`, Bike is a vehicle but not a car
You've met the humble home of generics.
Generics provide kind of 'wildcard' type where a class or method can specify that 'we don't really care what type it is, we just need -a- type'.
Generics allow a super class to enforce a specific type in a child class instead of allowing any class that extends a certain class.
This means that you're ultimately enforcing a new highest allowed super-class as the parameter (i.e. Vehicle is no longer the most basic allowable type you can pass to fix(); it's now whatever the subclass says it is, so long as that arbitrary type extends Vehicle).
Common places for generics are container classes (i.e. List, Map, and Set) where the container doesn't really care about what type it tracks, but rather focuses on actually tracking and managing those instances.
Generics consist of one or more type placeholders (in Java, E and T are commonly used but the name doesn't really matter; they usually follow the normal type naming conventions) that are used in place of a specific class or super class.
In your code, you want subclasses to implement methods given their exact relevant types (i.e. a CarFixer would take Cars, a JetpackFixer would take Jetpacks) but you want to enforce that these types extend Vehicle.
In order to enforce this, you have to tell the Fixer class exactly what your subclass wants.
public abstract class Fixer <E extends Vehicle>
{
abstract void fix(E vehicle);
}
Your subclass then extends Fixer, filling in E with the type it wants.
public class CarFixer extends Fixer<Car>
{
#Override
void fix(Car vehicle)
{
// ...
}
}
Lets say I have an abstract class:
public abstract class Trainer<T extends Animal>{
...
}
I'd like all child classes to have a common method that checks the training status of a trainer on a given animal. So I have in my Trainer definition:
public abstract class Trainer<T extends Animal>{
public double getStatus(Animal a){
...
}
}
so that anyone can query a trainer regardless of it's specific type. However, to make the individual trainers responsible for reporting their own status, I requiring a that the individual trainers implement an internalGetStatus method which I'd then like my getStatus method to call. So what I'm currently doing is:
public abstract class Trainer<T extends Animal>{
protected abstract internalGetStatus(T theAnimal);
public double getStatus(Animal a){
return internalGetStatus((T) a);
}
}
The problem is, of course, return internalGetStatus((T) a); involves an unchecked type cast which throws up a warning I'd like to avoid.
Is there a way to do that?
Because of some design limitations beyond my control, when the status is being queried for a particular animal, it is provided as an object of the parent class Animal and not the specific animal type that the trainer is created for.
It depends on how the classes are used. However, you didn't say much about that. Let's start with the following code:
abstract class Animal { }
final class Lion extends Animal { }
abstract class Trainer<T extends Animal> {
public abstract double getStatus(T animal);
}
final class LionTrainer extends Trainer<Lion> {
public double getStatus(Lion lion) {
return 4.2;
}
}
You mentioned that the call-side of the getStatus method doesn't know the animal type. That means he isn't using Trainer<Lion>, but either the raw type, Trainer<Animal> or a wildcard type. Let's go through these three cases.
Raw Type: The type parameter doesn't matter for raw types. You can invoke the method getStatus with Animal. This works as long as the sub-types of Trainer and Animal match. Otherwise, you will see a ClassCastException at runtime.
void raw(Trainer trainer, Animal animal) {
trainer.getStatus(animal);
}
Trainer<Animal>: Obviously, you can invoke the method getStatus of an Trainer<Animal> with an Animal. It similar to the above case. The static type system doesn't ware, and at runtime you will see an exception, if the types don't match.
void base(Trainer<Animal> trainer, Animal animal) {
trainer.getStatus(animal);
}
Note that you can pass a LionTrainer to this method (with cast), because at runtime there is no difference between Trainer<Animal> and Trainer<Lion>.
Wildcard Type: Well, that does not work on the caller-side - without casting the Trainer<?> to something else. The ? stands for an unknown sub-type of Animal (including the base class itself).
void wildcard(Trainer<?> trainer, Animal animal) {
trainer.getStatus(animal); // ERROR
}
The result is, if the framework uses either the raw type or the base type, then there shouldn't be a problem. Otherwise it's simpler to add the cast to your code, suppress the warning with an annotation, and document why you have decided to go that way.
I have an abstract Class Monitor.java which is subclassed by a Class EmailMonitor.java.
The method:
public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)
is defined in Monitor.java and must be overridden in EmailMonitor.java.
I currently have the method overridden in EmailMonitor.java as follows:
#Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
//...unrelated logic
return emailAccounts;
}
However, this produces the compile time error:
Name clash: The method performMonitor(List<EmailAccount>) of type EmailMonitor has the same erasure as performMonitor(Lis<? extends MonitorAccount> emailAccounts) of type Monitor but does not override it
EmailAccount is a subclass of MonitorAccount, so (in my mind at least) overriding it in this way makes perfect sense. Seeing as the compiler is not happy with my logic though, How should I go about this correctly while still keeping my compile time checks to make sure that all calls to EmailMonitor.performMonitor() receive Lists of EmailAccount rather than some other type of MonitorAccount?
No, it's not overriding it properly. Overriding means you should be able to cope with any valid input to the base class. Consider what would happen if a client did this:
Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);
There's nothing in there which should give a compile-time error given your description - but it's clearly wrong.
It sounds to me like Monitor should be generic in the type of account it can monitor, so your EmailMonitor should extend Monitor<EmailAccount>. So:
public abtract class Monitor<T extends MonitorAccount>
{
...
public abstract List<? extends T> performMonitor(
List<? extends T> accounts);
}
public class EmailMonitor extends Monitor<EmailAccount>
{
#Override
public abstract List<? extends EmailAccount> performMonitor(
List<? extends EmailAccount> accounts)
{
// Code goes here
}
}
You might want to think carefully about the generics in the performMonitor call though - what's the return value meant to signify?
Here is my own solution. I suspect this is the same thing Jon Skeet was trying to get at... without the typo (see my comment in reply to his answer).
the Monitor.java class:
public abstract class Monitor <T extends MonitorAccount> {
...
public abstract List<T> performMonitor(List<T> accounts);
..
}
EmailMonitor.java
public class EmailMonitor extends Monitor<EmailAccount> {
...
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
..//logic...logic...logic
return emailAccounts;
}
...
}
In this configuration, EmailMonitor.performMonitor() will always check at compile time that it receives a list of EmailAccount rather than any of my other types FTPAccount, DBAccount, etc... It's much cleaner than the alternative, which would have been receiving/sending a raw list and then having to coerce it the required type resulting in potential runtime type casting exceptions.