Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Study guide: Trash talk, Part 1

Brush up on Java terms, learn tips and cautions, review homework assignments, and read Jeff's answers to student questions

  • Print
  • Feedback

Page 2 of 2

Homework

This month, you have three questions to answer:

  1. Why is it beneficial that Java, rather than the developer, frees objects?
  2. Write a program that demonstrates how you can run out of memory in a Java program. What happens when you run out of memory?
  3. What is a disadvantage to a generational garbage collector? (Hint: Why does the Train algorithm exist?)


Answers to last month's homework

Last month, I asked you to trace the initialization process through the Employees source code below (assume that java Employees starts the program):

Employees.java

// Employees.java
class Employee
{
   private String name;
   private double salary;
   static int count;
   static double bonus;
   Employee (String name, double salary)
   {
      this.name = name;
      this.salary = salary;
      if (this instanceof Accountant)
          this.salary += bonus;
   }
   static
   {
      // Pretend to load bonus from a database.
      bonus = 500.0;
   }
   {
      if (count > 5)
          bonus = 0.0;
      count++;
   }
   String getName ()
   {
      return name;
   }
   double getSalary ()
   {
      return salary;
   }
}
class Accountant extends Employee
{
   Accountant (String name, double salary)
   {
      super (name, salary);
   }
}
class Employees
{
   public static void main (String [] args)
   {
      String [] names =
      {
         "John Doe",
         "Jane Smith",
         "Jack Jones",
         "Bob Smyth",
         "Alice Doe",
         "Janet Jones"
      };
      double [] salaries =
      {
         40000.0,
         50000.0,
         30000.0,
         37500.0,
         52000.0,
         47000.0
      };
      for (int i = 0; i < names.length; i++)
           if (i < 3)
           {
               Employee e = new Employee (names [i], salaries [i]);
               System.out.println ("Name = " + e.getName ());
               System.out.println ("Salary = " + e.getSalary ());
           }
           else
           {
               Accountant a = new Accountant (names [i], salaries [i]);
               System.out.println ("Name = " + a.getName ());
               System.out.println ("Salary = " + a.getSalary ());
           }
   }
}


When run, Employees produces the following output:

Name = John Doe
Salary = 40000.0
Name = Jane Smith
Salary = 50000.0
Name = Jack Jones
Salary = 30000.0
Name = Bob Smyth
Salary = 38000.0
Name = Alice Doe
Salary = 52500.0
Name = Janet Jones
Salary = 47500.0


How does Employees achieve that output? The following numbered list takes you through the program's execution and itemizes all initialization steps until the last Accountant object finishes initializing:

  1. The JVM's class loader loads Employees.class into memory, and the JVM's byte code verifier verifies all byte code instructions in that class.
  2. Because class Employees declares no class fields, the JVM does not allocate memory for class fields and zeroes all bits comprising that memory.
  3. The JVM starts executing Employees's main() method. Memory is allocated on the method call stack for local variables names, salaries, i, e, and a.
  4. The main() method's byte code instructions create a names array and a salaries array. References to those arrays (whose memory exists on the JVM's object heap) assign to local variables names and salaries.
  5. The for loop statement byte code instructions begin to execute. Zero assigns to local variable i.
  6. Because i's value (0) is less than names.length's (6), for executes the if decision statement.
  7. if evaluates i < 3. Because i's value (0) is less than 3, the byte code instructions comprising Employee e = new Employee (names [i], salaries [i]); start to execute.
  8. The JVM detects the presence of class Employee in those instructions and has its class loader load Employee.class. The JVM's byte code verifier then verifies all byte code instructions comprising that class.
  9. Because class Employee declares two class fields (count and bonus), the JVM allocates memory for those class fields and zeroes all bits comprising that memory.
  10. The JVM executes Employee's <clinit> method. That method assigns 500.0 to bonus.

  11. The JVM allocates memory for an Employee object's name and salary instance fields, and zeroes all bits comprising that memory. A reference to that object's memory is placed in a temporary stack location.
  12. The JVM executes the <init> method corresponding to Employee(String name, double salary).
  13. The <init> method first calls Object's no-argument <init> method, which does nothing and subsequently returns.
  14. The <init> method next executes an if decision statement's byte code instructions that evaluate count > 5. Because count currently contains 0, 0.0 does not assign to bonus.
  15. The <init> method next executes the equivalent of count++. count now contains 1.
  16. The <init> method next assigns the reference in its name parameter to the name field and the double-precision floating-point value in its salary parameter to the salary field.
  17. Finally, the <init> method uses the byte code equivalent of instanceof to see if the current object is an instance of Accountant. Because the object is not such an instance, nothing further happens and <init> exits.
  18. The JVM takes the Employee object's reference from the temporary stack location and assigns it to local variable e.
  19. The two System.out.println() method calls result in calls to Employee's getName() and getSalary() methods for the object referenced by e. Those methods return the appropriate name and salary values, which subsequently print.
  20. The for loop statement increments i (which becomes 1), and checks to see if i's value is still less than names.length's (6) -- which it still is. Therefore, the if decision statement executes a second time.
  21. Because the next two iterations (where i contains 1 and 2) repeat previous steps, let's continue where i contains 3.
  22. if evaluates i < 3. Because i's value equals 3, the byte code instructions comprising Accountant a = new Accountant (names [i], salaries [i]); start to execute.
  23. The JVM detects the presence of class Accountant in those instructions and has its class loader load Accountant.class. The JVM's byte code verifier then verifies all byte code instructions comprising that class.
  24. Because class Accountant declares no class fields, the JVM does not allocate memory for class fields and zeroes all bits comprising that memory.
  25. Because class Accountant contains no class initializers, there is no <clinit> method to execute.
  26. The JVM allocates memory for an Accountant object's name and salary instance fields (which are located in the Employee layer), and zeroes all bits comprising that memory. A reference to the Accountant object is placed in a temporary stack location.
  27. The JVM executes the <init> method corresponding to Accountant(String name, double salary).
  28. The <init> method first calls Employee's two-argument <init> method.
  29. Employee's <init> method calls Object's no-argument <init> method, which does nothing and subsequently returns.
  30. Employee's <init> method next executes the if decision statement that evaluates count > 5. Because count currently contains 3, 0.0 does not assign to bonus.
  31. Employee's <init> method next executes the equivalent of count++. count now contains 4.
  32. Employee's <init> method next assigns the reference in its name parameter to the name field and the double-precision floating-point value in its salary parameter to the salary field.
  33. Finally, Employee's <init> method uses the byte code equivalent of instanceof to see if the current object is an instance of Accountant. Because the current object is such an instance, the contents of bonus (500.0) are added to the salary field.
  34. Employee's <init> method exits to Accountant's <init> method.
  35. Accountant's <init> method has nothing further to do, so it exits.
  36. The JVM takes the Accountant object's reference from the temporary stack location and assigns it to local variable a.
  37. The two System.out.println() method calls result in calls to Accountant's inherited getName() and getSalary() methods for the object referenced by a. Those methods return the appropriate name and salary values, which subsequently print.
  38. The for loop statement increments i (which becomes 4), and checks to see if i's value is still less than names.length's (6) -- which it still is. Therefore, the if decision statement executes a second time.
  39. Because the next two iterations (where i contains 4 and 5) repeat previous steps, let's continue where i contains 6.
  40. Now that i contains 6, the for loop statement, followed by main(), exits. Before main() exits, the JVM releases memory for the local variables from the method call stack.


  • Print
  • Feedback

Resources