We have used Java to do calculations and to append strings, but we have not stored the results. The results would be in memory but we don't know where they are in memory and we can't get back to them. On a calculator we can store the result of one calculation to memory (Figure 2.4). We can then use that stored value in other calculations. On a calculator you also have access to the result of the last calculation.
Figure 2.4. A calculator with a number in memory.
2.4.1. Declaring Variables
On a computer we can store many calculated values by naming them. We can then access those values by using the variable names. The computer takes care of mapping the name to the memory location (address) that stores the value. We call naming values declaring a variable.
When you declare a variable in Java you specify the type for the variable and a name (type name). You need to specify a type so that Java knows how many bits to reserve in memory and how to interpret the bits. You can also assign a value to a variable using the '=' operator and provide a value or an expression (type name = expression). Don't read '=' as equals but assign the value of the right side to the variable on the left (which makes using '==' for 'is equal to' or 'is equivalent to' make more sense). The bits in the variable will be set to represent the value. We will use the type int for storing integer values (numbers without decimal points) and the type double for storing floating point values (numbers with decimal points).
2.4.2. Using Variables in Calculations
What if you want to calculate the total bill for a meal including the tip? You would start with the bill value and multiply it by the percentage you want to tip (20%), that would give you the tip amount. You could then add the tip amount to the bill total to get the total amount to leave.
We will use the type double to store the bill amount, tip, and total amount since these can have decimal points. If we also wanted to calculate the cost per person we could divide the total by the number of people. We could use an integer variable to hold the number of people.
> int numPeople = 2; > System.out.println(numPeople); 2 > double bill = 32.45; > System.out.println(bill); 32.45 > double tip = bill * 0.2; > System.out.println(tip); 6.490000000000001 > double total = bill + tip; > System.out.println(total); 38.940000000000005 > double totalPerPerson = total / numPeople; > System.out.println(totalPerPerson); 19.470000000000002
So, each person would need to pay $19.47, which they would probably round up to $19.50.
We don't have to print out the value of the variable after we assign a value to it. We are doing that so that you see that the computer does return a value when you use the name of a variable. What about the extra amount for the final answer? The answer should be just $19.47 per person. If we look back at the printing of the tip amount we see where this first occurred. Floating point numbers do not always give exact results.
2.4.3. Memory Maps of Variables
In Java when you declare variables to be of the type int or double you are asking the computer to set aside space for a variable of that type (32 bits for int and 64 for double) and to remember the address of that space. When you assign a value to a variable using the '=' operator you change the value in that space to represent the new value. The code int numPeople reserves 32 bits of space and associates the name "numPeople" with that reserved space (Figure 2.5). The code = 2 sets the value of that space to the integer value 2. The code double bill reserves 64 bits of space and associates the name "bill" with that space. The = 32.45 changes the values in the reserved space to represent the value 32.45.
Figure 2.5. Declaring primitive variables and memory assignment.
When we print out a variable name using System.out.println(bill); the computer looks up the name bill to find the address of that variable in memory and prints the value stored in that space. It knows how many bytes to use and how to interpret the bytes in calculating the value based on the declared type of the variable.
How would you calculate the cost of a shirt that was originally $47.99, but is now 40% off? And, what if you also had a coupon for an additional 20% off the sale price? First you would need to determine the first discount amount by multiplying 40% (0.40) times the original price. Next, calculate the first discount total by subtracting the first discount amount from the original price. Then calculate the second discount amount by multiplying 20% (0.20) times the second discount amount. The second discount total is the first discount total minus the second discount amount. We would need variables to hold the first discount amount, first discount total, second discount amount, and second discount total. What type should those variables be declared to be? Since they have fractional parts they can be declared as double.
> double originalPrice = 47.99; > double firstDiscountAmount = originalPrice * 0.40; > System.out.println(firstDiscountAmount); 19.196 > double firstDiscountTotal = originalPrice - firstDiscountAmount; > System.out.println(firstDiscountTotal); 28.794 > double secondDiscountAmount = firstDiscountTotal * 0.20; > System.out.println(secondDiscountAmount); 5.758800000000001 > double secondDiscountTotal = firstDiscountTotal - secondDiscountAmount; > System.out.println(secondDiscountTotal); 23.0352
When these statements are executed 64 bits of space is reserved for each variable declared as a double. So how much memory does this calculation take? We have declared five doubles so we have used 5 times 64 bits of space. Each byte has eight bits in it so how many bytes have we used? How much memory does your computer have and how much of it have you used? If your computer has 128 megabytes of memory then that is 128,000,000 bytes of memory and we used 40 bytes then we have only used 0.0000003125% of memory. That isn't very much. We can declare lots of variables and still not use up all of the memory.
Each time we use the variable name above the computer substitutes the value in the memory location associated with that name. What are the values in each of the five declared variables when these statements are finished?
2.4.4. Object Variables
Variables that are declared to be of any of the primitive types: byte, short, int, long, float, double, boolean or char reserve space and associate the variable name with the starting location of that space. Variables that are declared to be of any other type are object variables. This is because all other types inherit from the class Object.
You can think of inheritance as saying that one class "is a kind of" another class, like saying that a dog is a kind of mammal (Figure 2.6). If you need a mammal you can use a dog, but if you need a dog another mammal (like a cat) won't do. Because a dog is a kind of mammal we know that it has the same characteristics that a mammal does such as breathing oxygen, bearing live young, having hair, etc. We say that it inherits characteristics from mammal. The String class is a child of the Object class so it is a kind of object (Figure 2.6). All of the classes that you define will inherit from the Object class either directly or indirectly.
Figure 2.6. Showing the parent and child relationship between mammal and dog (left) and Object and String (right).
Once we have declared variables we can reuse them by assigning new values to them.
> String myName = "Mark"; > System.out.println(myName); Mark > myName = "Barb"; > System.out.println(myName); Barb
This actually means to first set the variable myName to refer to the String object with the characters "Mark" in it. Then it changes the variable myName to refer to another String object with the characters "Barb" in it. The first String object with the characters "Mark" in it still exists and can be garbage collected (reused as available space) (Figure 2.8).
You can't declare the same variable name twice. Declare the name one time (by specifying the type and name) and then you can use it many times.
> String myName = "Mark"; > System.out.println(myName); Mark > String myName = "Sue"; Error: Redefinition of 'myName'
The binding between the name and the data only exists (a) until the name gets assigned to something else or (b) you quit DrJava or (c) you reset the interactions pane (by clicking on the RESET button). The relationship between names and data in the interactions pane only exists during a session of DrJava.
You can have several variables that reference an object. You can use any of the references to access the object.
> String name1 = "Suzanne Clark"; > System.out.println(name1); Suzanne Clark > String name2 = name1; > System.out.println(name2); Suzanne Clark
When the compiler encounters the characters inside the pair of double quotes it creates a String object. The code String name1 creates a variable name1 that will refer to this string object. Print out name1 to see what it refers to using System.out.println(name1);. Next the code String name2 = name1; creates another variable name2 and sets the value of it to refer to the same string. Printing the new variable name2 will result in the same string being printed (Figure 2.9).
An object can only be garbage collected when there are no current references to it. To allow the String object with the characters "Suzanne Clark" in it to be garbage-collected set the variables that refer to it to null.
> name1 = null; > System.out.println(name1); null > System.out.println(name2); Suzanne Clark > name2 = null; > System.out.println(name2); null
Now all references to the String object are set to null so the object can be garbage-collected (Figure 2.10).