1

So I have an ArrayList of objects of unknown type extending Entity (my own class; not to be confused java.swing.text.html.parser.Entity) for reasons unrelated to this problem.

private ArrayList<? extends Entity> listedEntities = new ArrayList<>();

This is in a class that in its constructor receives a String and assigns it to the field entityClass.

At some point I am executing the following piece of code:

    Class<?> clazz = Class.forName(this.entityClass);
    Object newEntity = clazz.newInstance();

    listedEntities.add(newEntity);

Naturally, this doesn't work as the ArrayList is expecting an object of a class extending Entity and newEntity is of Object. So first thing was to try casting.

listedEntities.add(Class.forName(this.entityClass).cast(newEntity));

Also doesn't work. And after a few minutes not finding an answer I am here typing this.

The exception:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The method add(capture#8-of ? extends Entity) in the type ArrayList<capture#8-of ? extends Entity> is not applicable for the arguments (capture#9-of ?)
2
  • 2
    How about forgetting about ? and use some T Commented Jan 15, 2017 at 20:50
  • Is there a good reason that you are using String for entityClass instead of a Class? Commented Jan 15, 2017 at 20:57

1 Answer 1

4

A simple solution is like this:

  • Change listedEntities to ArrayList<Entity> instead of ArrayList<? extends Entity>. It doesn't look like you have a particular reason to use the wildcard and the wildcard prohibits you from adding to the list.

  • Change your construction to this:

    Class<?> clazz = Class.forName(this.entityClass);
    Entity newEntity = (Entity) clazz.newInstance();
    
    listedEntities.add(newEntity);
    

This will solve the compilation error and it's type-safe in that the explicit cast will throw an exception if somehow this.entityClass is not some subtype of Entity.

A fully-generic version as I believe @RC. hints at in the comments would be like this:

class Example<E extends Entity> {
    private List<E> listedEntities = new ArrayList<>();
    private Class<E> entityClass;

    Example(Class<E> entityClass) {
        this.entityClass = entityClass;
    }

    void method()
    throws IllegalAccessException, InstantiationException {
        E newEntity = entityClass.newInstance();
        listedEntities.add(newEntity);
    }
}

That is more 'proper'; however, whether you can use something like it or not depends on your specific needs.


As a side note, the fact that your error is thrown as an exception worries me a little bit. You should use a proper IDE which will flag compilation errors like that in the editor so you don't have to run the program to find them.

Sign up to request clarification or add additional context in comments.

6 Comments

Regarding the side note: I'm using Eclipse Neon 2.0 but the exception is an exception due to having the following entry point - public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new Primary(); }}); }
Well that seems fine. I think it should still flag the error during compilation but unfortunately I don't know enough about Eclipse to say why it might not in this case.
Regarding the proposed solution: It doesn't fulfil my needs to use an ArrayList<Entity>. Actually that was the initial version before using reflection at all. I need to have objects of the same class and that class needs to extend Entity. The fully generic version also doesn't do me good for one reason: The class I am in is defined as Lister<E> and it never is the same as the class the ArrayList holds.
If you've lost the type of the list you assign to listedEntities, you could convert it to ArrayList<Entity> by copying it e.g. listedEntities = new ArrayList<Entity>(theSourceList). For the generic version, unless I'm misunderstanding, you could just add a second type variable like Entity<E, T extends Entity>. It's a bit hard to offer a better suggestion without knowing more about those restrictions. I already emphasized this briefly, but the wildcard will simply have to go if you want to add to listedEntities. See e.g. stackoverflow.com/q/2723397/2891664.
No, of course, I could add a second type variable, but the thing is at the moment of initialisation of the variable of class Lister I still don't know the class extending Entity that will be required. As I said, your answer was helpful and it pushed me towards resolving the problem. Thanks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.