You need to let go of the idea that you must assign a symbol to every object you create. Symbols (variable names) are defined at compilation time, but you can write programs that create an arbitrary number of objects at runtime, without you knowing what to call them in advance.
Consider public static void main(String[] args). How would you handle giving a variable name to every String in args? You could try to be smart and lay out a bunch of variables in advance:
public static void main(String[] args) {
String s1 = (args.length > 0) ? args[0] : null;
String s2 = (args.length > 1) ? args[1] : null;
String s3 = (args.length > 2) ? args[2] : null;
String s4 = (args.length > 3) ? args[3] : null;
String s5 = (args.length > 4) ? args[4] : null;
}
But what will you do if you run into more than that? What if you need to support thousands of possible command line arguments? You cannot possibly predict this in advance, of course.
In fact, this is the exact reason why main takes a String[] and not multiple Strings. The number of command line arguments cannot be known in advance, so an array is necessary. And the only way you have to refer to them is by their indices in the array.
In the absence of symbols, you can use many methods of lookup on elements in a data structure (such as an array, a List, or a Map).
Data structures such as Lists and arrays can be iterated over. Say you want to find the kitten named "puss", you can go through each kitten in the List until your find the one you want:
kitten pussTheKitten;
for (kitten k: sackOfKittens) {
if (k.getName().equals("puss")) {
pussTheKitten = k; // found it!
}
}
Alternatively, you can utilize the powerful Map data structure to make it faster and easier to get objects based on some unique "key" attribute:
Map<String, kitten> mapOfKittens = new HashMap<String, kitten>();
for (kitten k: sackOfKittens) {
mapOfKittens.put(k.getName(), k);
}
kitten pussTheKitten = mapOfKittens.get("puss"); // found it!
set()method ofArrayListor just useadd()