Way to handle multiples of the same item?

I have a question about this piece of code I wrote today.

public void actionPerformed(ActionEvent evt) {
		Ammo ammo = new Ammo();
		Ammo.numAmmo++;
		label.setText("Number of ammo objects created: " + Integer.toString(Ammo.numAmmo));
	}

When I compile, and click a button any number of times, the number of ammo objects created goes up. How can this be when if I do something like this

Ammo ammo = new Ammo();
Ammo ammo = new Ammo();

the compiler gives me an error? If I were making a game that had ammo objects, how would I make multiples of the same object then? Where would they all live, in the program itself? Should I put them into a master array? Thanks.

In your first bit of code the variable ‘ammo’ is created then discarded when the actionPerformed() method ends. That’s why you can call the method many times; because the variable ceases to exist each time the methos exits, so next time it’s OK to make a new one. The variable has method-wide scope.

In the second bit of code you create a variable ‘ammo’ then immediately try to create another variable with the same name in the same scope - so you get an error.

Using a master (or class-wide scope) array is a good idea - define it in your class but not in a method.

Your first code is equivalent with this code:


public void actionPerformed(ActionEvent evt) {
		Ammo.numAmmo++;
		label.setText("Number of ammo objects created: " + Integer.toString(Ammo.numAmmo));
	}

So it doesn’t really count the number of Ammo objects created (it counts how many times that actionPerformed method is called) and breaks encapsulation. Try something like this if you want to count how many Ammo objects have been created:


public void actionPerformed(ActionEvent evt) {
		new Ammo();
		label.setText("Number of ammo objects created: " + Integer.toString(Ammo.objectsCreated()));
	}

Ammo.java:


public class Ammo {
  private static int numAmmo = 0;
  public Ammo() {
    numAmmo++;
  }
  public static int objectsCreated() {
    return numAmmo;
  }
}


You could put all the objects into a List or some other data structure, so that you can get access to them. For example like this:


public class AmmoStorage() {
  private List<Ammo> ammos = new ArrayList<Ammo>();

  public void addOneAmmo() {
    ammos.add(new Ammo());
  }

  public int numberOfAmmos() {
    return ammos.size();
  }
}

Let’s say Player A has some ammo and Player B has some ammo, and they both dropped their ammo on the ground. Then Player C comes a long and picks up 2 ammo objects. Wouldn’t it get confusing whose ammo is whose? (If it were happening on a larger scale.) Or is it unimportant? Would it matter if the entire game contained thousands of ammo objects that all have the same name? (Programmatically. Not that they’re all called “ammo,” but that within the program they’re all named “ammo.”)

I think you’re confusing the concepts of variable declaration and object identity.

In the following code there are declared three variables “ammo1”, “ammo2” and “ammo3”. But there is only one object instance - the one created with the “new” keyword. In this code ammo1, ammo2 and ammo3 are all references to the same object. You might say that there is one Ammo which is known by three names.


Ammo ammo1 = new Ammo();
Ammo ammo2 = ammo1;
Ammo ammo3 = ammo1;

Likewise, in the following code a total of ten Ammo objects are created. Inside the first for-loop the “ammo” variable exists only a short while - it is created and destroyed on every loop. But the lifespans of the Ammo objects continue even after the loop, because they are added into the “ammos” collection. When all the ammos are printed in the latter loop, you will see that all the objects have a different identity (by default they will print as something like Ammo@123, Ammo@124, Ammo@125 etc.). Inside the first loop the Ammo objects are known by the variable name “ammo”, between the loops they don’t have a variable name, and in the latter loop they use the variable name “a”.


Collection<Ammo> ammos = new ArrayList<Ammo>();
for (int i = 0; i < 10; i++) {
    Ammo ammo = new Ammo();
    ammos.add(ammo);
}
for (Ammo a : ammos) {
    System.out.println(a);
}

Modify your Ammo class to look as below, and then run the above code. Experiment with it and read about the basics of object-oriented programming until you understand fully why it prints:
I’m Ammo #1
I’m Ammo #2
I’m Ammo #3

I’m Ammo #10

Ammo.java:


public class Ammo {
  private static int nextNumber = 1;
  private final int number;
  public Ammo() {
    number = nextNumber;
    nextNumber++;
  }
  public String toString() {
    return "I'm Ammo #" + number;
  }
}