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)
Foo object is created, with all fields
set to 0/0.0/false/null.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.
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.java | Ex01.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 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?
public double distance() { return Math.sqrt(x*x+y*y); }
... or a method to reflect a point with respect to the y
axis:
public void reflectMeXAxis() { y = -y; }
Assuming we had a Point p already, these would be called
like
double d = p.distance(); and like
p.reflectMeXAxis();.
Note:
What you'll find is that non-static (i.e. instance
methods) is what you'll typically be doing.
Why? Because only instance methods will allow for
polymorphism, one of the fundamental mechanisms
of OOP ... which we'll cover soon.
nextDouble() method
of Random returns a random number in the
range [0,1].)
public static Point randomPointInUnitSquare(Random rand)
{
return new Point(rand.nextDouble(),rand.nextDouble());
}
Think about it this way: If you were to make this a member
function, what would you do with the this
pointer? Overwriting values in an existing point is
undesireable, because then you have a two-step process of
creating a point with dummy values for x and y, and then
calling the function to modify those. The other option is
to make a constructor that takes a Random
object and does this, but that's undesireable if you also
wanted to create points that were randomly distributed in
the unit circle.
Another great situation for a static method rather than a
constructor or an instance method that modifies an
object is when
you sometimes will want to return a value that signals
that the object you wanted couldn't be created.
Reading from stdin to get a new point is an example.
The read will fail if the user doesn't give you the
right kind of data. If we have a static read function
that returns a reference to the new Point that is read
in, we can signal that something went wrong by
returning null. You can't do this with a
construtor or a method that is supposed to modify an
object.
Consider a "read" function for Points:
public Point(Scanner sc) { ... } // Bad because you can't "return" null
public void read(Scanner sc) { ... } // Bad because you can't "return" null
public static Point read(Scanner sc) { ... } // Good because you can return null if something goes wrong
Note: in a few weeks we'll talk
about exceptions which will give us another way
to handle this kind of thing.
public boolean equal(Point B) { return this.x == B.x && this.y == B.y; }
or with
public static boolean equal(Point A, Point B) { return A.x == B.x && A.y == B.y; }
so that with Point's A and B you would either call with
A.equal(B)
or with
Point.equal(A,B)
You might prefer the static version because it treats both
points the same: neither is "special", whereas with an
instance method, one Point (A) "owns" the equality test.
However, the Object-oriented philosophy says:
make in an instance method unless there is a
compelling reason not to. In other words, when
in doubt make it an instance method.
The reasons for this involve inheritance and polymorphism,
which we haven't seen yet.
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.1in 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.
| x/y bounds | height, 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. |
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;
}
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.
TimeOfDay.
growBy.
/**
* 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;
}
}
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.
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