简体   繁体   中英

Java generics - Class<?> constructor argument issue

I've used Java for quite some time now, but some things are still not very clear to me, especially when it comes to generics...

Here's the thing: I have this Search class that I'm using ( see here for details ), that is constructed like this:

public Search(Class<?> searchClass) {...}

Further more, I have a parametrized generic wrapper around this, as follows:

public class HibernateSearch<E> extends Search implements Serializable {
    public HibernateSearch(Class<E> entityClass) {
        super(entityClass);
    }
    // ... omitted for brevity
}

Now, what I need is the following: I'd like to create parametrized class, that contains this class as its field, eg

public class BaseSelectorComposer<T> extends SelectorComposer<Window> {

    private HibernateSearch<T> searchObject;
    ...
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        super.doAfterCompose(comp);
        this.searchObject =
             new HibernateSearchObject<T>( now what...??? );
        ...
    }
    ...
}

I think that the problem I'm facing is obvious from the given example.
Can someone advise what can be done here, or some alternative ?

The easiest way would be to pass the responsibility on to whoever actually instanciates and uses instances of BaseSelectorComposer , ie:

public class BaseSelectorComposer<T> extends SelectorComposer<Window> {

    private HibernateSearch<T> searchObject;
    private final Class<T> theType;

    public BaseSelectorComposer(Class<T> token) {
        theType = token;
    }

    ...
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        super.doAfterCompose(comp);
        this.searchObject = new HibernateSearchObject<T>(theType);
        ...
    }
    ...
}

If your BaseSelectorComposer is an abstract subclass, which is only ever used like

class IntSelectorComposer extends BaseSelectorComposer<Integer> {
    ...
}

ie, as base class for classes, which "bind" the type parameters, there are ways to obtain the type information via reflection (though this is incredibly ugly, since this is not really well-supported in the API IMHO).

In general, this is a hard-to-workaround scenario. Coming from .NET background, I have personally found very few cases where I could work this out, since Java does not support static generic type resolution (like for instance in .NET where you can use typeof(T) ).

To work this around I recommend that you find a way to either get the class externally, or an instance of that class. A possible solution would be to change the doAfterCompose method in one of the following ways:

@Override
public void doAfterCompose(Window comp, Class<?> entityClass) throws Exception {
    super.doAfterCompose(comp);
    this.searchObject =
         new HibernateSearchObject<T>(entityClass);
    ...
}

-or-

@Override
public void doAfterCompose(Window comp, SomeEntity entity) throws Exception {
    super.doAfterCompose(comp);
    this.searchObject =
         new HibernateSearchObject<T>(entity.getClass());
    ...
}

If you cannot modify the method signature (I see it is an override), try to use a member of the class BaseSelectorComposer<T> that will hold the desired Class<?> instance.

public class BaseSelectorComposer<T> extends SelectorComposer<Window> {
    private Class<?> entityClass;

    public BaseSelectorComposer<T>(Class<?> entityClasss) {
        this.entityClass = entityClass;
    }

   ....
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        super.doAfterCompose(comp);
        this.searchObject =
            new HibernateSearchObject<T>(this.entityClass);
       ...
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM