TheDude1142
TheDude1142

Reputation: 188

Java: ArrayList in Superclass

I am having a terrible time with using an ArrayList in a superclass. The ArrayList is used to hold objects of three different types of subclasses of superclass Enemy. Depending on how I reference an object in the ArrayList in the driver file dictates different results.

Enemy is a child of a superclass called fighter. Fighter holds the private data for all of the objects.

Here is the superclass Enemy.

import java.util.*;

public class Enemy extends Fighter {
    public void getRandomEnemy(){};
    public ArrayList<Enemy> enemy = new ArrayList<Enemy>();

    Enemy(String wep, String arm, String nam, int health, int magResis, int physResis, int rangResis)
    {
        super(wep,arm,nam,health,magResis, physResis,rangResis);
    }
}

For Example:

Two of Enemy's subclasses Troll and Sorcerer have objects of their respective types added to the ArrayList found in the parent class Enemy.

Troll and Sorcerer Constructors:

Sorcerer(String wep, String arm, String nam, int health, int magResis, int physResis, int rangResis)
    {
        super(wep,arm,nam,health,magResis, physResis,rangResis);
    }

Troll(String wep, String arm, String nam, int health, int magResis, int physResis, int rangResis)
    {
        super(wep,arm,nam,health,magResis, physResis,rangResis);
    }

I am adding objects to the ArrayList in superclass enemy through these methods. Each method is found in its respective class.

public void getRandomEnemy()
    {
        enemy.add(new Troll("Bow", "Leather", "Troll",350, 30, 15,30));
    }

public void getRandomEnemy()
    {
        enemy.add(new Sorcerer("Staff", "Cloth", "Sorcerer",300, 70, 5,5));

    }

Now in my driver file if I add objects of types troll and sorcerer to the ArrayList in enemy as such.

Driver file:

int p = 5; // adds 5 enemies to the ArrayList enemy
int randEnemy = 0;
        for(int i =0; i < p; ++i)
        {

            randEnemy = (int) (Math.random() * (3));

            if(randEnemy == 0)
            {
                sorc.getRandomEnemy();
            }
            else if(randEnemy == 1)
            {
                trol.getRandomEnemy();
            }
            else
            {
                og.getRandomEnemy();
            }
        }

This is where I begin to run into issues. For example, if I want to return the size of ArrayList enemy. The total size I have to do this in my driver file.

int size = sorc.enemy.size() + trol.enemy.size() + og.enemy.size();

I have to call each specific object type and add them together.

If I do Enemy.enemy.size(); It will return 0.

Again, things get fishy with the ArrayList when I want to attack an enemy.I have to specifically look for each Sorc object or Troll object in the ArrayList.

for(Enemy j : sorc.enemy)
                {   
                    System.out.println("Sorc's Health: " + j.getHealth());
                    System.out.println("Sorc's Armor: "+ j.getArmor());
                    sorc.takeDamage(attack, "Cloth", weapon);
                }

If I do the code above I will get the correct health for the Sorcerer which is 300 and I will get the correct armor. But, the Sorcerer will not take any damage.

If I do this:

for(Enemy j : sorc.enemy)
                {   
                    System.out.println("Sorc's Health: " + j.getHealth());
                    System.out.println("Sorc's Armor: "+ j.getArmor());
                    j.takeDamage(attack, "Cloth", weapon);
                }

The health will return -1999234 or some random negative value,but the takeDamage() method will work perfectly.

My question is why when I reference the object differently, I get different results? How do I properly reference the objects in the ArrayList to ensure the proper values are getting set? I am sure it isn't a logic error because I am setting the values in the constructors and calling the constructors in the getRandomEnemy() method to add objects to the ArrayList.

EDIT: Issue Fixed

In the superclass Fighter the constructor is defined as such.

public Fighter(String wep, String arm, String nam, int health, int magResis, int physResis, int rangResis)
    {
        this.name = nam;
        this.weapon = wep;
        this.armor = arm;
        this.health = health;
        this.magicResistance = magResis;
        this.physicalResistance = physResis;
        this.rangedResistance = rangResis;
    }

Health was giving me the issue. It was the only variable turning out wonky data. As you see, the parameter has int health, and I am setting that argument that is passed through to this.health = health;

Even though I am using this. to distinguish between the the parameter and the instance variable, the value was coming out negative.

I simply changed the constructor to this:

public Fighter(String wep, String arm, String nam, int hea, int magResis, int physResis, int rangResis)
    {
        this.name = nam;
        this.weapon = wep;
        this.armor = arm;
        this.health = hea;
        this.magicResistance = magResis;
        this.physicalResistance = physResis;
        this.rangedResistance = rangResis;
    }

and now everything works.

Upvotes: 1

Views: 3980

Answers (1)

Richard
Richard

Reputation: 527

I think your problem is a misunderstanding of how the members of a super class work.
When you declared:

public class Enemy extends Fighter {
    public ArrayList<Enemy> enemy = new ArrayList<Enemy>();
}

Every object of type Enemy or a subclass of Enemy will have their own instance of the enemy List. They will not share the same list.
Also you are mixing up different object members:

Sourcerer sourcer = new Sourcerer();
sourcer.getHealth(); // this is a member of the object just created;
sourcer.enemy;  // is a list of Enemy type objects
                // this list is a member of the sourcer object

for(Enemy enemy : sourcer.enemy) {
      enemy; //is an object in the list
            //this object should not be sourcer object (see below)
}

sourcer.enemy.add(sourcer); //is valid but will make a really big mess
                            //so make sure you never do this. 

If you want your objects to share the same list from the super class, you need to declare it static.
I would suggest you make a separate class which manages the battle and have the list there. This way you separate the individual characters (Fighters, Enemies, Sorcerer, Trolls) from the management of groups of characters (battle).

Upvotes: 5

Related Questions