Java Chapter 8 - Classes

8.1 Basic Class

Classes are what makes Java an object-oriented programming (OOP) language.  They allow you to create a custom object to model a real-world object.  Objects have both data and methods (functions).

For example, a class could be defined to model a pair of dice.  The data for the object is the numbers that are showing on top.  The method for the object is to roll the dice.  Once a class (object) is defined, then the main program can create one or more instances of class.  This is similar to defining a variable.  Below is an example of declaring and using an instance of the Dice class:

   MyDice Jack = new MyDice();              // Declare an instance of MyDice named Jack
   Jack.Roll();                            
// Roll the dice
   System.out.println(Jack.Value());       
// Print the value of the dice

The program below defines a cube class (MyCube).  The data consists of the length, width, and height.  It has one method that returns the volume of the cube.  The main program defines an instance of MyCube.  The MyCube class initializes values of length, width, and height to zero.

Classes

public class cube1
{
   public static void main(String[] args)
   {
      MyCube Valerie = new MyCube();

      Valerie.Length = 3;
      Valerie.Width = 3;
      Valerie.Height = 3;

      System.out.println("Valerie has volume of " + Valerie.Volume());
   }
}

class MyCube
{
  
// Class variables are declared and initialized to zero
   public int Length = 0, Width = 0, Height = 0;

   int Volume()
   {
      return Length * Width * Height;
   }
}
Output
Valerie has volume of 27


8.2 Variable Initialization and Constructors

In the preceding program, the Length, Width, and Height variables are initialized to zero by default.  An alternative way to initialize variables is from within a constructor.  A constructor is a method with the same name as the class, and is executed when an instance of a class is created.  In addition to initializing variables, can perform additional setup and be used to accept parameters from the main program when an instance of the class is created:

MyCube Valerie = new MyCube(3,3,2);    // Send 3,3,2 as parameters to the new MyCube named Valerie

The program below allows instances of MyCube to be declared with or without parameters.  Remember that when there are multiple methods of the same name that take different parameters, it's called overloading the methods.

Constructors

public class cube2
{
   public static void main(String[] args)
   {
     
// Vicky initialized without using parameters.
      // This constructor sets defaults: Length=1, Width=1, Height=1

      MyCube Vicky = new MyCube();
      System.out.println("Vicky has volume of " + Vicky.Volume());

     
// Valerie initialized with parameter values Length=3, Width=3, Height=2
      MyCube Valerie = new MyCube(3,3,2);
      System.out.println("Valerie has volume of " + Valerie.Volume());
   }
}

class MyCube
{
   public int Length, Width, Height;

   // Constructor used if no parameters are sent. It sets default values.
   public MyCube()
   {
      Length = 1;  Width = 1;  Height = 1;
   }

   // Constructor used when parameters are sent to initialize variables
   public MyCube(int L, int W, int H)
   {
      Length = L;  Width = W;  Height = H;
   }

   public int Volume()
   {
      return Length * Width * Height;
   }
}

Output
Vicky has volume of 1
Valerie has volume of 18


8.3
Data Hiding

It is good programming practice to protect the data within a class through data hiding.  All variables declared within a class should be made private so that the main program cannot access the variables directly.  A new accessor method is created to access the variables.  Look at the code below:

Public access to variables

public class cube1
{
   public static void main(String[] args)
   {
      MyCube Valerie = new MyCube();

      Valerie.Length = 3;    
// main program can set variables directly
      Valerie.Width = 2;
      Valerie.Height = 4;

      System.out.println("Valerie has volume of " + Valerie.Volume());
   }
}

class MyCube
{
  
public int Length, Width, Height;   // main program can access public variables

   public int Volume()
   {
      return Length * Width * Height;
   }
}

Private variables (data hiding)

public class cube1
{
   public static void main(String[] args)
   {
      MyCube Valerie = new MyCube();

      Valerie.setLength(3);
      Valerie.setWidth(2);
      Valerie.setHeight(4);

      System.out.println("Valerie has volume of " + Valerie.Volume());
   }
}

class MyCube
{
  
private int Length, Width, Height;   // main program cannot access private variables

   public void setLength(int L) 
// accessor method to set Length
   {  Length = L;  }

   public void setWidth(int W) 
// accessor method to set Width
   {  Width = L;  }

   public void setHeight(int H) 
// accessor method to set Height
   {  Height = H;  }

   public getLength()   
// accessor method to set Length
   {  return Length;  }

   public getWidth()
    // accessor method to set Width
   {  return Width;  }

   public getHeight()   
// accessor method to set Height
   {  return Height;  }

   public int Volume()
   {
      return Length * Width * Height;
   }
}

Why data hiding?  Why should all access to class variables be performed through methods?  It provides an interface for any changes to variables.  This interface (accessor method) allows for data validation, logging, and prevents accidental modification of the variables from the main program.  For example, suppose that each dimension of a MyCube must be between 0 - 9.  Below, we have created a SetDimensions accessor method that performs data validation - if any of the dimensions is greater than 9, it sets it to 0.

Accessor method with data validation

public class cube3
{
   public static void main(String[] args)
   {
      MyCube Valerie = new MyCube();

     
// Since the width cannot be set to -1, it is defaulted to 0.
      Valerie.SetDimensions(5,-1,3);

      System.out.println("Valerie has volume of " + Valerie.Volume());
   }
}

class MyCube
{
   private int Length, Width, Height;  
// all variables are private

   // Constructors
   public MyCube(int L, int W, int H)
   {
      Length = L; Width = W; Height = H;
   }

   public MyCube()
   { }

   // The method used to set variables now does data validation.
   // If a dimension is not within range (0 - 9), it is set to 0.
   public void SetDimensions(int L, int W, int H)  
   {
      if (L >= 0 && L <= 9)  Length = L;
      else Length = 0;

      if (W >= 0 && W <= 9)  Width = W;
      else Width = 0;

      if (H >= 0 && H <= 9)  Height = H;
      else Height = 0;
   }

   public int Volume()
   {
      return Length * Width * Height;
   }
}

Output
Valerie has volume of 0


8.4 Static Variables

In a class definition, variables that are preceded by the keyword "static" become a shared variable among all instances of the class.  That is, each class member addresses the same variable instead of having their own value for the variable.  Consider the following class:

class Player
{
   int Health = 100;
   String Name;
   static NumberOfPlayers;

   Player(String newName)
   {
      Name = newName;
      NumberOfPlayers++;
   }
}

Below is a program to demonstrate use of a static variable.  Each instance of the Player class (A, B, and C) have their own Name variable.  However, there is only one NumberOfPlayers variable since it is static.  If Player A changes the value of a static variable, then Player B sees the new value.

Static Variables

public class game
{
   public static void main(String[] args)
   {
      Player A = new Player("Drax");
      Player B = new Player("Groot");
      Player C = new Player("Rocket");

      System.out.println("Name = " + A.Name + " Number Of Players = " + A.NumberOfPlayers);
      System.out.println("Name = " + B.Name + " Number Of Players = " + B.NumberOfPlayers);
      System.out.println("Name = " + C.Name + " Number Of Players = " + C.NumberOfPlayers);
   }
}

class Player
{
   int Health = 100;
   String Name;
   static int NumberOfPlayers;

   Player(String newName)
   {
      Name = newName;
      NumberOfPlayers++;
   }
}

Output
Name = Drax  Number Of Players = 3
Name = Groot  Number Of Players = 3
Name = Rocket  Number Of Players = 3