Creating an instance of an object in Array List supplied by another ArrayList?

     I have a class that I want to use JUST for the sole purpose of storing all of my different entities in the game. This way I can retrieve a certain entity randomly. In another class I also have an entity Array List that's for the actual game play. How would I be able to create a new instance of an entity from the first array list in the second Array List? I tried doing the same process as just about anything else but I started getting options like adding a static suppress warning and a bunch of other thingamajigs that I do not understand.

First:

public class EntityList {
	
	public static  ArrayList<Entity> entityList;
	
	public EntityList(){
		entityList = new ArrayList<Entity>();
		
		entityList.add(new Orc());
		
	}

}

2nd Class:

	switch(tileSetting){
			case "Friendly":
				break;
			case "Hostile":
                                WANT TO CREATE INSTANCE OF ENEMY HERE.
				break;
			}

If you just want to be able to instantiate random classes, then just do that, ditch the bureaucracy. (at least as much as is possible in Java…)


case "Hostile": // consider using an enum variant here instead of typo-able strings
    doSomethingWith(randomEnemy());
break;

...

static List<Class<Entity>> enemyClassList; // fill this somewhere with class objects e.g. add(Orc.class)

public static Entity randomEnemy() {
   // warning: assumes list isn't empty!
   return enemyClassList.get((int) (Math.random() * enemyClassList.size())).newInstance(); // alternatively use a java.util.Random with nextInt(n)
}


Wooo! Thank you for the tips! Didn’t know you could add an extra set of these thingamajigs <> to an array list!

It’s not “to the array list”, it’s the Class type:

List<Class> = List of ( Class objects that represent some sub-type of ( Entity ) )

https://docs.oracle.com/javase/tutorial/java/generics/

Oooooooh, thanks for that. I’ll make sure to read through the whole thing.

Actually now I seem to be having a problem. When I do as above I get this error:

[quote]The method add(Class) in the type List<Class> is not applicable for the arguments (Class)
[/quote]
Orc implements the Entity class.

Ah, try List<Class<? extends Entity>>.
I wondered if that would happen.

I’d advise not getting bogged down with generics.

They’re a huge jump in complexity with very little added value; a terrible concept for new developers to waste their time understanding.

Turn off your ide’s warnings and avoid using them until you’ve mastered every other aspect of Java.

You would need List<? super Class<? extends Entity>> in order to statically “add” Classes of subtypes of Entity to the list.
But then you would not be able to statically “get” any Class of Entity from that list; you would get the static type “Object” back.

The original proposition of List<Class<? extends Entity>> tells Java, that the list contains Class’es of things being a subtype (and all of the same subtype!) of Entity. But the compiler would not know, which exact subtype that would be.
The compiler also tells you that you could only add null to the list, because it cannot statically validate that whatever Class of subtype of Entity you add to the list would be the same thing that is already in the list. Only null can be safely cast to anything else.
Getting something from that list however would work, since the compiler knows that whatever is in the list is in any case a Class of at least Entity. And therefore, this is what you would “get”.

I aggree with @Abuse that the concept of parameterized types is very advanced.
And the horrible, horrible implementation of that concept in the form of “Java Generics” makes things even worse.
Just ignore generics and use the raw types.
You get compiler warnings about possible “heap pollution” (the “unchecked” warnings) every here and there, but just ignore them!

But hey, why are you not just using enums like @BurntPizza suggested.
And I would add that you even do not need/want reflection but a simple switch-case over all your enemy types with normal “new” instantiation would also do fine.

EDIT: Maybe a bit more about why List<? extends Enemy> tells Java that this List would only contain instances of the exact same subtype of Enemy, as stated above.

Normally, we would think that this List can contain instances of any subtypes of Enemy and we wonder why the compiler then would not allow us to “add” some different enemies to it.

The problem probably is that we generally assume that List<? extends Enemy> can contain any combination of instances of any subtypes of Enemy, because we are dealing with something called a “List” here and we are telling the List that it contains anything extending from Enemy.
But this thinking unfortunately leads into the wrong direction.

The fact is that type List<? extends Enemy> tells Java that this “List” deals with instances of exactly one subtype of Enemy.
Which one, however, cannot be known. Hence the wildcard “?”.

The problem here is that the type system of Java unfortunately has no notion of lists, contrary to other languages that feature this built-in type, such as Haskell.
The java.util.List is just a normal parameterized interface.
It is just that we assume from the word “List” and from the fact that we can “add” to and “get” something from it, that the type parameter would apply to each element of the list individually. But this is not so.

It seems the simple issue here is that MrPork wants one ArrayList containing a list of enemy types and another containing enemy instances. Hopefully the first reply shows the problem with the original code which is that to have a list of types you need ArrayList or similar, and not ArrayList.

The way you can manipulate types (i.e. classes) as objects at runtime in Java is a really good feature of the language IMO, partly because it supports a lot of common application usage - as here - with brief, elegant code like BurntPizza’s example. I wouldn’t say it’s an “advanced” topic as in conceptually hard (obviously it’s not!) but I suppose the danger is of trying to use it when in 99.99% of cases the better and more elegant way is to do things at compile time.

Here it seems a reasonably intuitive approach, but as KaiHH said a simple case switch would probably be just as good, and arguably better for readability and creating less class bloat in the project :slight_smile:

e.g.

//Create random enemy
int diceRoll = rollDice(2,6);
if (diceRoll == 1) return new Orc();
if (diceRoll == 2) return new Skellington();

Yes, introspection (RTTI as C++ calls it) and the Java Reflection API are great features of Java!
And those are definitely not complicated, I aggree.
But the implementation of “parameterized types” as Java Generics is insane, especially if you pair this with reflection and type erasure (as opposed to the different “template” approach taken by C++ and C#) and getting things such as only partly reifyable types.
And I have not yet gotten into things such as covariance and contravariance with wildcard types… :-/
Considering all this, in my humble opinion understanding Generics in Java is the hardest part of the language, because it’s the most inconsistent. :wink: