CSE5910 : Multimedia Programming in Java

Lecture : More Object Oriented Programming Concepts in Java

In the previous lecture:

In this lecture:



Java Classes and Objects

Here is a revised version of the specification of a class Point2D.

/** Point2D represents a Cartesian point in 2 dimensions */
public class Point2D
{
   private double xCoordinate;  // "private" indicates that coordinates aren't accessible outside the class
   private double yCoordinate;  // and prevents methods outside the class changing the values without the class knowing


   // A default constructor (it has no parameters) that sets the default values
   // for the fields. If one of these default constructors is not written
   // Java will provide one but it will set x and y coordinates to the default integer value (0)
   // unless you specify other default values in their declaration above. (e.g. private double xCoordinate=1.0;)
   // Constructors do not have a return type, not even "void".
   public Point2D()
   {
    xCoordinate = 1.0;
    yCoordinate = 1.0;
   }
   // A constructor that takes parameters. Although it is not necessary, it is possible to
   // have parameter names that match class field names. To distinguish between them
   // inside the method use the "this" keyword to indicate the fields of "this" object that
   // the method has been called to create (or act upon).
   public Point2D(double xCoordinate, double yCoordinate)
   {
    this.xCoordinate = xCoordinate;
    this.yCoordinate = yCoordinate;
   }

   // Since the coordinates are now "private", we need to write "set" and "get" methods that
   // allow controlled access to these data members from outside the class.
   public void setCoordinates(double xCoordinate, double yCoordinate)
   {
    this.xCoordinate = xCoordinate;
    this.yCoordinate = yCoordinate;
   }

   public double getXCoordinate()
   { return xCoordinate; }

   public double getYCoordinate()
   { return yCoordinate; }
   public void Print()
   { System.out.println("x=" + xCoordinate + " y=" + yCoordinate); }
   public double distanceFromOrigin()
   { return Math.sqrt(xCoordinate * xCoordinate + yCoordinate * yCoordinate); }
}

A Labelled-Point2D that extends Point2D

/** LabelledPoint2D represents a Cartesian point in 2 dimensions with a text label */

// The keyword "extends" in the class declaration of LabelledPoint2D indicates that the
// LabelledPoint2D "is a" Point2D (it will also have some extra features... in this case, a label).
public class LabelledPoint2D extends Point2D
{
   // This is a "class field" (as opposed to an instance field). Because it is labelled
   // "static". This means that there is a *single* variable defaultLabel that belongs to *all* members of
   // the class LabelledPoint2D instead of there being an individual variable defaultLabel
   // for every LabelledPoint2D that is instantiated. The keyword "final" makes this variable
   // unchangeable (constant).
   private static final String defaultLabel = "untitled";

   // This class inherits the coordinates from Point2D so in it we only add new fields and
   // methods that are specific to this subclass. Such as a place to put the label for the point...
   private String label;

   // Get into the habit of always writing a constructor that takes no parameters for your class and
   // sets each new object up with default prarameters.
   public LabelledPoint2D()
   {
     label = defaultLabel;
   }
   // A constructor for the labelled point that passes the coordinates through to the
   // constructor of its "super class" (parent in the class hierarchy) using the "super" keyword.
   public LabelledPoint2D(double xCoordinate, double yCoordinate, String label)
   {
    super(xCoordinate, yCoordinate);
    this.label = label;
   }

   // Since the label is "private", we need to write methods that
   // allow controlled access to it from outside the class.
   public void setLabel(String newLabel)
   { label = newLabel; }

   public String getLabel()
   { return label; }

   public void resetLabel()
   { label = defaultLabel; }
   
   // This Print() method *over-rides* the Print() method of its superclass (Point2D) to handle the label
   // but depends on it to print out the x and y coordinates (since LabelledPoint2D knows
   // nothing about these coordinate values... they are the sole responsibility of the super class Point2D).
   // Over-riding refers to the specification of a method in a sub-class that matches the return type, parameter
   // list and method name of a method in the superclass. In this way, the sub-class can
   // respond to a method call in a way that is more specialised than the behaviour of the more general super class.
   public void Print()
   { System.out.println("label: " + label);
     super.Print();
   }
}

Making Objects

How do we actually make and use Point2Ds and LabelledPoint2Ds?

public class PointTester
{
    public static void main(String[] args)
    {       
        Point2D point = new Point2D(3.0, -5.0);
        LabelledPoint2D labelledPoint = new LabelledPoint2D(4.0, 5.0, "my label");
                              
        // Call method: Point2D.Print()
        point.Print();

        // Call method: Point2D.distanceFromOrigin()
        System.out.println(" of distance from origin: " + point.distanceFromOrigin());
        
        
        // Call method: LabelledPoint2D.Print()
        labelledPoint.Print();

        // Call method: Point2D.distanceFromOrigin()
        // There is no method LabelledPoint2D.distanceFromOrigin()
        // because the method was *not* over-ridden by the derived class.
        System.out.println(" of distance from origin: " + labelledPoint.distanceFromOrigin());
    }
} 

Packages

There are thousands of classes written by other programmers that we can employ as part of our own programs. This saves us reinventing software for common tasks (e.g. for handling Strings).

A package is a collection of classes and other reference types (and "interfaces"...something we've not yet discussed) that is bundled together and named.

Examples of basic Java packages include:

If you want to use a class that exists in a package of Java code you can access it using its full name.

Code in the java.lang package is so fundamental to the language you don't need to do this for its contents (e.g. String). But if you wanted to use the File class to do file i/o you could decalare a File object like this:

java.io.File myFile; // a tedious and verbose way to declare a file

Alternatively you can import the package so that its contents' names are part of the current "namespace" like this:

import java.io.File; // Import the File class

File myFile; // Now we can declare File variables more simply

If we also wanted to use other classes (besides File) from within the io package we can tell Java to automatically import any classes that we need from the package like this:

import java.io.*; // Import any class that our code needs from the io package


A summary of access to class data members and methods

public members Accessible anywhere inside or outside the class.
private members Accessible anywhere inside the class in which they are defined.
Not accessible directly from outside.
protected members Accessible anywhere inside the class in which they are defined.
Accessible from within any other classes that are part of the same package.
Accessible within any sub-class of the class in which they are defined regardless of which package defines the sub-class.
Not accessible from outside the package.
members of unspecified access If a member does not have an explicit private, public or protected status it adopts the default status i.e. it is accessible to code within all the classes defined in its package.
It is not accessible by default outside of the package in which it was defined.

 

Tip Always use the most strict constraints on accessability that are possible.
The less accessible a member is, the easier your code will be to debug and the easier it will be to write reliable code building upon it as a base
.

 

  Member accessability
(I.e. Can the code indicated at left access a member declared with the accessability keyword listed below?)
Accessing code Public Protected Private
Defining class Yes Yes Yes
Different class in same package Yes Yes No
Subclass (derived class) in different package Yes Yes No
Non-subclass in different package Yes No No

Class fields and Class methods and the static keyword.

As we saw briefly in the LabelledPoint2D class, we can use the keyword static to create a data member that belongs to the class as a whole, instead of to each individual instance of the class. We do this so that all instances of the class can share a common variable. The static keyword ensures that there is only one instance of the variable in memory, instead of there being one instance of the variable in each instance of the class.

Fields defined without the static keyword are called "instance fields" because they belong to each instance of a class.

Fields defined with the static keyword are called "class fields" because they belong to the class as a whole.

Example: If we define a class Circle, every Circle instance will need it own instance field to hold its radius. However, all Circles can share a common class field for a value like Pi.

Here's another example...

public class CountedClass
{
    // Create a private static variable and set its initial value.
    // Why should the variable be private?
    private static int numberOfInstancesCreated = 0;

    public CountedClass()                    // The constructor for the class
    { numberOfInstancesCreated++; }          // Keep track of how many instances of this class have been created

    public int getNumberOfInstancesCreated()
    { return numberOfInstancesCreated; }
}

We can also use the static keyword on methods. We've seen it on main() many times because the program can only have one main method, not one main method for every instance of the class in which main() is defined.

Sometimes we want a method that is associated with the class, a "class method" instead of a method associated with each instance of that class, an "instance method".

We can use instance methods only on instances of the class using the syntax we've already seen:

objectName.instanceMethod(parameters);

To access a class method we write:

className.classMethod(parameters);

Inside the class in which the class method is defined, we don't actually need to specify the class in order to call the method but it makes it clearer if we do so.

public class Circle
{
    public static final float Pi = 3.142;                           // Create a static, final class field and set its value
    private float radius = 0.0;                                     // Create an instance field

    public Circle(float radius)                                     // The constructor for the class
    { this.radius=radius; }                                         

    public static DegreesToRadians(float thetaDegrees)              // A class method that isn't specific to each circle
    { return thetaDegrees * Circle.Pi / 180.0; }                    // but allows a useful, relevant conversion to be made from degrees to radians

    public float arcLength(float thetaDegrees)                      // A method to calculate the arc length of a section of this particular circle
    {
       float thetaRadians = Circle.DegreesToRadians(thetaDegrees);  // Call the class method
       return (thetaRadians * radius;)
    }
}

Home exercise 1 highly recommended...

Write a class A with a simple method and a single private member int a. Make the method print out "a=" and a's value. Make the constructor for the class print out "Making a new A". Write get() and set() methods for the data member a.

Write a class B that extends class A and over-rides its simple method and has a new data member int b. Make the method print out "b=" and b's value. Make the constructor for the class print out "Making a new B".

Write a class C that extends class B and over-rides its simple method and has a new data member int c. Make the method print out "c=" and c's value. Make the constructor for the class print out "Making a new C ".

Write a main() method for your program and try creating a few objects of different types A, B and C. What gets printed out? Why? Play around with the accessability of the different classes' data and method members and see how Java behaves. Chain the calls to the constructor and the simple method using the super keyword as in the example above. Try printing out the values of a and b from within class C. What other combinations are possible? Which are impossible? Why? Make certain you thoroughly understand what is going on :-)


Home exercise 2 highly recommended...

Find out about abstract classes and methods. You will need this information to understand interfaces.

What are they? What are they for? How are they written? (e.g. see Flanagan, Java In A Nutshell pp128-130 (5th edn.))

Build an abstract class and use it to derive some concrete classes. Make sure you understand how they work.



Lecture summary:

 



CSE5910 Courseware | CSE5910 Lecture Notes