when i try to instantiate an object, from a class that extends a generic abstract class. It won't let me since the generic abstract class does not have a suitable constructor.
public abstract class AbstractClass<T> {
private final Class<T> entityClass;
public AbstractClass(Class<T> entityClass) {
this.entityClass = entityClass;
}
}
this is the generic abstract class I am talking about.
public class Imp extends AbstractClass {
public Imp(Class entityClass) {
super(entityClass);
}
}
If i want to ever access the Imp class, then I would try to instantiate it through a normal constructor. But i get following error when trying:
public class Imp extends AbstractClass {
public Imp(){
}
public Imp(Class entityClass) {
super(entityClass);
}
}
constructor AbstractClass in class AbstractClass cannot be applied to given types required: Class
So if i understand correctly, by extending a generic abstract class you cannot instantiate the class anywhere ever?
If not being able to access the Imp class from other classes, how should I ever use the class?
you need to extend it like that:
public class Imp<T> extends AbstractClass<T> {
public Imp() {
super(null); // you need to call an existing constructor from superclass (nothing specific about generic classes)
}
public Imp(Class<T> entityClass) {
super(entityClass);
}
}
Never use a generic class without generic parameters.
Just guessing, but maybe you actually want something like this:
public class IntegerImpl extends AbstractClass<Integer> {
public IntegerImpl () {
super(Integer.class);
}
}
If you want to use a no-arg constructor to initialize Imp class, then AbstractClass should have this (no-arg) constructor as well, but 'entityClass' property cannot be final anymore in this case.
This could lead to possible null pointer exceptions if you use 'entityClass' without not null checks.
Related
I have a DAO object that I'd normally extend with the entity class name like so:
public class DAO<T> {
private final Class<T> clazz;
public DAO(Class<T> clazz {
this.clazz = clazz;
}
}
public class EntityDAO extends DAO<Entity> {
public EntityDAO() {
super(Entity.class);
}
}
However, I have some abstract entities that I would like to create an abstract DAO that gets implemented into a concrete class later on:
public class DAO<T> {
private final Class<T> clazz;
public DAO(Class<T> clazz {
this.clazz = clazz;
}
}
public abstract class AbstractEntityDAO extends DAO<T extends AbstractEntity> {
public AbstractEntityDAO () {
super(AbstractEntity.class);
}
}
public abstract class EntityDAO extends AbstractEntityDAO <Entity> {
public EntityDAO() {
super(Entity.class);
}
}
But this doesn't work as the AbstractEntityDAO complains about an unexpected bound and it cannot resolve T. Is it possible to do this? And if so, how is it written?
This is using Java 1.7
Put the generic type definition on AbstractEntityDAO:
public abstract class AbstractEntityDAO<T extends AbstractEntity> extends DAO<T> {
...
}
With your current code AbstractEntityDAO <Entity> should make the compiler complain about AbstractEntityDAO not having generic paremeters.
Besides that your AbstractEntityDAO() constructor needs to accept a Class parameter as well. However, you don't need to pass the class as a parameter at all if you always use instances of classes with concrete types. Using reflection a class can determine the type of T if there is a concrete definition as in EntityDAO. The built-in reflection utilities provide no easy way to do this but fortunately you only need a little additional code to provide one, have a look here: http://www.artima.com/weblogs/viewpost.jsp?thread=208860
That's basically what we're doing as well. Here's a rough rundown of our approach:
abstract class BaseDAO<T> {
Class<?> entityClass;
BaseDAO() {
//this is based on the link I posted above but basically uses the actual concrete class
//(subclass determined by getClass() ) to extract the generic types and
//since we only have one we get the first one from the returned list
entityClass = ReflectionHelper.getTypes(getClass(), BaseDAO.class).get(0);
}
public T getEntity(Object id) {
...
}
}
abstract class TranslatableDAO<T extends TranslatableEntity> extends BaseDAO<T> {
...
}
//Users are not translatable
class UserDAO extends BaseDAO<User> {
...
}
//Products are translatable, i.e. Product extends TranslatableEntity
class ProductDAO extends TranslatableDAO<Product> {
...
}
I have an interface, a superclass that implements it, and a subclass that extends the superclass. Then I have test that creates an object of the type of the subclass, but stores it in a variable of the type of the interface. When I use a method that is defined in the interface, implemented in the superclass, and overridden in the subclass, it calls the method from the superclass. Why is this? I can't change the test class, but did I do something wrong with the subclass?
public interface SampleInterface<T extends Comparable<T>>{
void add(T element);
//other methods, etc
}
public class SampleClassA<T extends Comparable<T>> implements SampleInterface<T> {
public void add(){
System.out.println("super");
}
}
#Override
public class SampleClassB<T extends Comparable<T>> extends SampleClassA<T> {
public void add(){
System.out.println("sub");
}
}
Then I want to use the code in a test that looks like this:
private SampleInterface<Integer> test = new SampleClassB<Integer>();
test.add();
And it prints "super", but I want "sub". This is a simplified version of my code, also.
I have an abstract class (Candy) with a generic collection (Flavors). Candy has a factory method to produce concrete instances of itself. It also has methods to get an instance of the generic flavor appropriate to the concrete candy and to add the flavor to its collection.
I know the getter is working, because if I cast the flavor from the CandyStore, the methods unique to the concrete flavor work fine. But the very last line, the addFlavor(flavor), errs (Eclipse) on me. The error is: "The method addFlavor(capture#5-of ? extends IFlavor) in the type ICandy is not applicable for the arguments (IFlavor)." Can anyone explain what is going on?
Interface:
public interface ICandy <Flavor extends IFlavor> {
public Flavor getFlavorForCandy();
public void addFlavor(Flavor flavor);
}
Abstract Class:
public abstract class AbstractCandy<Flavor extends IFlavor> implements ICandy<Flavor> {
public static ICandy<? extends IFlavor> buildCandy(String flavor){
if(flavor.equals("Jolly Rancher")
return new JolRanchCandy();
}
public Flavor getFlavorForCandy() {
return (Flavor) new CandyFlavor();
}
public void addFlavor(Flavor flavor) {
... //implemented
}
}
Concrete Class:
public class JolRanchCandy extends AbstractCandy<JolRanchFlavor> {
... //implemented
}
Used By:
public class CandyStore {
private ICandy<? extends IFlavor> candy;
private IFlavor flavor;
public void createCandy() {
candy = AbstractCandy.buildCandy("Jolly Rancher");
flavor = candy.getFlavorForCandy(); //returns a JolRanchFlavor
flavor.setName("Apple"); //etc for creating flavor
candy.addFlavor(flavor); //no luck
}
}
Edit: For clarity, JolRanchFlavor extends CandyFlavor implements IJolRanchFlavor and CandyFlavor implements IFlavor.
Try this...
public <T extends IFlavor> void createCandy() {
ICandy<T> candy= (ICandy<T>) AbstractCandy.buildCandy("Jolly Rancher");
T flavor= candy.getFlavorForCandy();
flavor.setName("Apple");
candy.addFlavor(flavor);
}
The problem is the declaration of private ICandy<? extends IFlavor> candy. Since the type of the candy is unknown and therefore ? the compiler doesn't know exactly what kind of IFlavor addFlavor should take. You just need to define a generic holder for the IFlavor type so that it is preserved.
If say I have some generic class, for example:
public class Attribute<T> {
}
Is it possible now to have specific methods for specific types? I.e. to extend the generic class for certain kinds of types?
For example:
I want to add extra methods to Attribute<String>, but not for say Attribute<Integer>.
There is no such direct possibility in Java.
But you can have StringAttribute that extends Attribute<String> and adds to it the methods you'd like to. You can make a kind of factory, in a dependency injection fashion, which will construct e.g. Attribute<Integer> for Integer and StringAttribute for String.
Not directly, but you can do this...
public class StringAttribute extends Attribute<String>
{
public String myNewMethod() ...
....
}
You can do something like this:
public abstract class Attribute<T> {
public abstract T getValue();
}
public class Attr1 extends Atrribute<String> {
#Override
public String getValue() {
return "smth"
}
}
Create an abstract class which will have the generic type T and abstract method with the same generic type. Then other classes can extend it by specifying real object instead of generic.
Your class should be abstract:
public abstract class Attribute<T> {
void someMethod(T object);
}
And then add subclasses such as:
public AttributeString<T extends String> extends Attribute<T>{
void someMethod(T object){
}
}
Within my code a have the following abstract superclass
public abstract class AbstractClass<Type extends A> {...}
and some child classes like
public class ChildClassA extends AbstractClass<GenericTypeA> {...}
public class ChildClassB extends AbstractClass<GenericTypeB> {...}
I'm searching for an elegant way how I can use the generic type of the child classes (GenericTypeA, GenericTypeB, ...) inside the abstract class in a generic way.
To solve this problem I currently defined the method
protected abstract Class<Type> getGenericTypeClass();
in my abstract class and implemented the method
#Override
protected Class<GenericType> getGenericTypeClass() {
return GenericType.class;
}
in every child class.
Is it possible to get the generic type of the child classes in my abstract class without implementing this helper method?
BR,
Markus
I think its possible. I saw this was being used in the DAO patterns along with generics. e.g.
Consider classes:
public class A {}
public class B extends A {}
And your generic class:
import java.lang.reflect.ParameterizedType;
public abstract class Test<T extends A> {
private Class<T> theType;
public Test() {
theType = (Class<T>) (
(ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
// this method will always return the type that extends class "A"
public Class<T> getTheType() {
return theType;
}
public void printType() {
Class<T> clazz = getTheType();
System.out.println(clazz);
}
}
You can have a class Test1 that extends Test with class B (it extends A)
public class Test1 extends Test<B> {
public static void main(String[] args) {
Test1 t = new Test1();
Class<B> clazz = t.getTheType();
System.out.println(clazz); // will print 'class B'
System.out.println(printType()); // will print 'class B'
}
}
I'm not sure I fully understand your question - <Type> is the generic type of the subclass, even when it's being expressed in the abstract class. For example, if your abstract superclass defines a method:
public void augment(Type entity) {
...
}
and you instantiate a ChildClassA, you'll only be able to call augment with an instance of GenericTypeA.
Now if you want a class literal, then you'll need to provide the method as you indicated. But if you just want the generic parameter, you don't need to do anything special.