Here it comes finally. Until now, everything has been public this and public that. What does that really mean?
public class WeaponList {
private int tally;
private String[] weaponName;
public WeaponList(int maxSize) {
weaponName = new String[maxSize];
tally = 0;
}
public void addWeapon(String weaponToAdd) {
if (tally < weaponName.length) {
// Still space left to add more names
weaponName[tally] = weaponToAdd;
tally++;
} else {
// No space let, we'll do nothing (for now)
}
}
public void printWeaponList() {
int i;
while (i < tally) {
System.out.println("Weapon " + i +
": " + weaponName[i]);
i++;
}
}
public String getWeaponAt(int i) {
if ((i < 0) || (i >= tally)) {
// Out of range
return null;
} else {
return weaponName[i];
}
}
public int getTally() {
return tally;
}
}
WeaponList wList =
new WeaponList(100); // Valid, constructor is PUBLIC
wList.addWeapon("Sling"); // Valid, method is PUBLIC
wList.addWeapon("Mace"); // Valid, method is PUBLIC
wList.printWeaponList(); // Valid...
wList.tally = 10; // Invalid... variable is PRIVATE
// why is this very IMPORTANT?
wList.weaponName[20] = "Axe"; // Invalid... again why is this IMPORTANT?
So, now we see that we can prevent variables from being changed.
Why? Imagine the other class chose to add weapons themselves, simply
placing values into the array without calling the method.
Then, it decides to call the method to PRINT the list.
Guess what? The object can't.
Why not, b/c the tally was not incremented at
the same time. The object (wList) does not know how many weapons
were added by the outside classes... it still thinks there are 0.
Of course, we could expect the outside class to increment the tally as well. But this defeats the purpose of writing a class to handle the task. Second, if the outside class had access to the tally variable, they could mistakenly change that value. For example, setting it to 10 when there are only 5 weapons, or 5 when there are in fact 10 on the list. In both cases, printing out the list (or whatever other methods there are for the class) would not work.
But, what if the outside class really wants to access a value or change one. And you also want the outside world to have some (limited) access to these variables. Sometimes this is necessary. You solve this by writing accessor methods.
In the above example, getTally() and getWeaponAt(int index) are both accessor methods to tally and the weaponName array. You may also have methods to set variables. In general, the naming convention is as follows:
public int getTally() {
return tally;
}
public void setTally(int newTally) {
tally = newTally;
}
Of course, in this example, it doesn't make sense to have setTally
as a method at all, or at least not a PUBLIC method (maybe PRIVATEly
would be reasonable.) But there are cases where you would allow
setting the variables with a method.
Essentially, the accessor method can control the access of the value
set or "gotten".
This is a harder rule to describe. If the method should be accessible outside, then make it public, if not, make it private. So, in practice, try to follow these rules and you'll be fine:
public interface Locatable {
public int getLocationX();
public int getLocationY();
}
This definition implies that any object which is Locatable
must have two methods (getLocationX() and
getLocationY()) implemented.
Here is how we would define such a class.
public class Human implements Locatable {
Stats theStats;
int positionX;
int positionY;
// ...
// Insert lots of methods and other variables here
// ...
// ...
public int getLocationX() {
return positionX;
}
public int getLocationY() {
return positionY;
}
}
In fact, somewhere inside the definition we actually implement these methods, getLocationX() and getLocationY(). In this case, we ignored all the other methods, but they would be there as well. Now, we can say that Human is Locatable.
Note: when it comes to naming interfaces, it is customary to use adjective names ending in "able"... e.g., Enumerable, Countable, Throwable, etc.
Using interfaces it is possible for another unrelated class to also
implement the same interface.
For example,
public class Item implements Locatable {
String itemName;
int coordinateX;
int coordinateY;
// ...
// Insert lots of methods and other variables here
// ...
// ...
public int getLocationX() {
return coordinateX;
}
public int getLocationY() {
return coordinateY;
}
}
Human personOne = new Human("Miss Scarlet");
Human personTwo = new Human("Colonel Mustard");
Item itemOne = new Item("Candlestick");
Item itemTwo = new Item("Wrench");
int x;
int y;
// These methods all work
x = personOne.getLocationX();
y = personOne.getLocationY();
x = itemOne.getLocationX();
y = itemOne.getLocationY();
Locatable objectToLocate;
objectToLocate = personTwo;
x = objectToLocate.getLocationX();
y = objectToLocate.getLocationY();
objectToLocate = itemTwo;
x = objectToLocate.getLocationX();
y = objectToLocate.getLocationY();
// The following does NOT work
objectToLocate = new Locatable();
// Locatable objects cannot be created.