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 ?)
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366

1 Answers1

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.

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • 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(); }}); } – Hristo Valchev Hristov Jan 15 '17 at 21:34
  • 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. – Radiodef Jan 15 '17 at 21:40
  • Regarding the proposed solution: It doesn't fulfil my needs to use an ArrayList. 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 and it never is the same as the class the ArrayList holds. – Hristo Valchev Hristov Jan 15 '17 at 21:40
  • If you've lost the type of the list you assign to `listedEntities`, you could convert it to `ArrayList` by copying it e.g. `listedEntities = new ArrayList(theSourceList)`. For the generic version, unless I'm misunderstanding, you could just add a second type variable like `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. http://stackoverflow.com/q/2723397/2891664. – Radiodef Jan 15 '17 at 21:51
  • It's a great clarification though. I'll have to move a lot of functionality down to a new class so I can go with the fully-generic version, but your answer is indeed helpful and I am marking it as accepted. – Hristo Valchev Hristov Jan 15 '17 at 21:52
  • 1
    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. – Hristo Valchev Hristov Jan 15 '17 at 21:57