Note: we did an in-class activity.

Reprising constructors

Suppose we have a class named Foo. The only way to instantiate an object of class Foo is with a "new-expression". To understand what happens when a new-expression is evaluated, consider an expression of the form:
new Foo(arg1, arg2, ..., argk)
  1. A new Foo object is created, with all fields set to 0/0.0/false/null.
  2. The k-argument constructor whose parameters match the types of arg1,...,argk is called with it's this pointer/reference pointing to the newly created Foo object. Note that the constructor does not return anything ... it's goal is just to perform initialization for the newly created object. You the programmer never "call" a constructor. It is called by the new operator.
  3. Once the constructor has completed, the evaluation of the new expression is complete. The value of the new expression is a reference to the newly created-and-initialized Foo object.

Note: If you do not have a constructor for a class, one will be created for you (the Miranda rights of OOP?). It will be a default constructor, which means a constructor with no arguments, and it simply initializes everything to 0/0.0/false/null. If, on the other hand, you create even just one constructor, then only the constructor(s) you create will be available — the compiler will not create one for you.

Example of a Constructor in Action
Point.javaEx01.java
public class Point
{
  private double x, y;
  
  public Point(double px, double py)
  {
    x = px;
    y = py;
  }
}
public class Ex01
{
  public static void main(String[] args)
  {
    double a = 0.5, b = 1.7;
    Point p;
    p = new Point(a,b);
  }
}

Static vs. non-static methods: how, why and which when? (Huh?)

Recall: a static method is just a regular old function — no this pointer is involved! Outside of the class, the call has to be prefaced with the class-name-"dot". A non-static method has a this-pointer, so it must be either called explicitly with an instance on the left (e.g. p.toString()) or called with an implicit this, which means that you're already in a member function where this.toString() and toString() are in fact synonymous.

So ... why would you choose to use a non-static in one case and a static in another?

Instance variables vs. local variables

With all the newness, don't be confused about local variables. They work just as they always have: they are born at their point of declaration, die at the end of that function-call/block, and are only ever visible within that function/block. Thus, they are the ultimate in "hidden". Nothing outside of that block can ever touch them. So there is no public/private annotations for them. No need to do it, and it's not allowed! Public/private/protected — the access modifiers — apply to class definitions, fields (a.k.a. data members), and methods (a.k.a. member functions).

Object Oriented Design: Deciding what code goes where

A program built on the Object Oriented Programming paradigm organizes its code differently than a procedural program — meaning that where the code offering a particular piece of functionality goes is different. Part of getting used to OOP is making the right kind of decisions about what goes where. We're going to look at a few design decisions you have to make for Lab 3 and try to figure out what the most Object-Orientedy way is.

The Setup Recall that we have thre classes: Point, Box and Lab03. The general OOP design philosophy says that the code that has to do with points, without any particular reference to Lab03 or bounding boxes or any other specific problem that might involve points, should go in the Point class. The code that has to do with bouning boxes in general, without any particular reference to Lab03 or any other specific problem that might involve bounding boxes, should go in the Box class. Everything that's left should go in class Lab03.

Decision 1 - Where to read the word "add": The user inputs something like

add 3.5 -1.1
in order to "add" a new point to the bounding box. That means that somewhere in the program there has to be a
String comm = sc.next();
if (comm.equals("add"))
{
  ...
But where should that code go? In class Lab03? In class Box? In class Point? It needs to go into class Lab03! Why? Because it's only in the context of this program the word "add" pertains to points and bounding boxes. Another program that wants to compute with points or compute with bounding boxes might never read from a Scanner at all, much less read the word "add" and expect it to add a point to a bounding box! If you put this code in Box or in Point, you might be able to get your lab solution to work, but you would limit the liklihood that the classes Point and/or Box would be useful to future projects — and you'd make the code for this project harder to write, debug and understand.

Decision 2 - Where to put the code that prints out boxes in the xmin < x < xmax, ymin < y < ymax format: You'll have to have some code to do this, where should it go? You might argue that it should go into class Lab03 because that's the output format we want for this program, not necessarily others. You might argue it should go into class Box, because what could be more "about boxes" than printing out a description of a box? You might argue that it should be in class Point, because you need to access the private fields x and y of some Points in order to do the printing (this depends on what fields you chose to use for your box implementation). So, what do we do?

This code belongs in the class Box! It's about a box, and this may not be the only way to "print" a box, but it's a very natural and common way. You could provide multiple formats in different functions if future programs wanted something different, but still relying solely on the box itself. As for the argument for putting it in class Point, the solution is to extend the functionality of class point by adding "getter" functions:

public double getX() { ... }
public double getY() { ... }
to provide the needed values to the Box class. After all, the Box class is hardly the only class that might want to know a Point's x and y coordinates.

Code Reuse: Make the most out of your Objects!

One of the promised benefits of adhering to the discipline of Object Oriented Programing is code reuse, the idea that we can expect to be able to easily make use of code written in one project in another project. It also suggests that we should try to make use of existing classes when we can. So, once again, let's revisit Lab 3 and some of the choices we made in writing code for that Lab. When it came time to implement the class Box, there are at least three natural ways to represent the Box with your private data.
x/y boundsheight, width and lower left point lower left and upper right points
We can represent a box by the values xmin, xmax, ymin and ymax. This is convenient for printing the way we have to. We could remember the box by a reference point (lower left is pretty standard) and the box's width and height. This is not particularly convenient for the problems we need to solve. We could represent a box by two points — the lower left and upper right points. If Point has the right methods, this can make things really convenient. What's nice, is that we benefit from our own code reuse, because we have all the Point methods at our disposal.

Initializing static fields (data members)

Non-static fields are initialized by constructors. What about static fields? There are two basic mechanisms for initializing them. The first is to give an initializing expression at the point at which the declaration takes place. E.g. the "= 0" in:
 private static int counter = 0;
But that doesn't work when there is code that needs to be executed, not just a simple expression. For this, we can add static initialization blocks or, more simply, we can add a static method and call it as the initializer expression, e.g.:
private static int[] squares = initSquares(10);

private static int[] initSquares(int n)
{
  int[] A = new int[n];
  for(int i = 1; i <= n; i++)
    A[i] = i*i;
}

The "final" modifier

In addition to public/private/protected and static, Java has a modifier "final". It means different things depending on whether it is used with a class, method or field definition. Its meanings for classes and methods involves inheritance, which we haven't yet studied, but its meaning with fields is pretty straightforward. A field, whether static or not, that is declared "final" never changes after it is given its initial value. So you might say something like:
private static final double PI = 3.14159;
... which means that PI is a double, it's a static field (a single variable PI shared by all instances of the class), it's private (can't be accessed outside of the class), and it's final, which means that it's value can never change from the 3.14159 it was originally assigned.

Java style

Java's API is a huge part of any Java program you write, and it follows a very strict set of conventions. Therefore, since we don't want two different sets of conventions running around, we always follow the same conventions in our code. The basics are:
  1. Class names begin with an upper-case letter and otherwise follow "Camel Case" — separate words are squished together, but each new word starts with a captial letter. E.g. TimeOfDay.
  2. Method and non-final field names begin with a lower-case letter and otherwise follow Camel Case. E.g. growBy.
  3. Constants (e.g. fields declared "final") are all upper-case.
  4. Comments should precede every method and every class definition, at a minimum. Java has a unique way of including comments for methods/classes that you should follow. It is not with the // characters:
    /**
     * This class does X, Y, and Z
     * You should use it!
     */
    public static class Commenter {
        /**
         * This method makes no sense, but the comments are great.
         */
        public String toString() {
           return "hellooooo";
        }
    
        /**
         * This method adds two numbers.
         */
        public int add(int num1, int num2) {
           return num1+num2;
        }
    
    }
    

Java's printf

Sometimes System.out.println( ) is painful to use. The PrintStream (which is what System.out is) also has "printf", which behaves similarly to C's printf. So for example:
public class Ex1
{
  public static void main(String[] args)
  {
    double x = 0.2373451, y = 1.8021234;
    System.out.printf("%1.3f divided by %1.3f is %1.5f\n",x,y,x/y);
  }
}
produces the following output when run
~/$ java Ex1
0.237 divided by 1.802 is 0.13170
See the documentation for more details.

Primitive wrapper classes

Java distinguishes between primitive types and objects primarily for performance reasons. It complicates things, though. Moreover, you sometimes want a double or an int to behave like an object — for example when you'd like to dinstinguish between the absence of a value (null) as opposed to a zero value (0 or 0.0). Java has class version of the primitive types, called Primitive wrapper classes. They are class Integer, Double, Character, Byte and Boolean. Objects of these types are immutable (like strings, they cannot be changed). Here's an example that uses the Integer class so that null can signal the absence of a value.
import java.util.*;

public class Ex2
{
  public static void main(String[] args)
  {
    Scanner sc = new Scanner(System.in);
    Integer I = null;
    while(I == null)
    {
      System.out.print("Enter an integer: ");
      if (!sc.hasNextInt())
	sc.nextLine();
      else
	I = sc.nextInt();
    }
    System.out.println("You entered " + I);
  }
}
Here's a sample run:
~/$ java Ex2
Enter an integer: I = 23
Enter an integer: twenty
Enter an integer: help?
Enter an integer: 23
You entered 23