Classes
Prelude: The Java String data type
- String is a built-ing data type representing character strings
- String variable can use standard initialization syntax
String s = "foo";
- Java overloads the + operator to cover String concatentation
"foo" + "bar" -> "foobar"
- String variables are reference types
String a = "foo";
String b = a; // a and b are 'eq', reference same object.
- Unlike integer variables, and like array variables, Strings involve
two units of memory, the String variable itself, and the storage
referenced by the string variable (string of characters).
- Stack vs heap storage
- String's are an example of a built-in object type.
- In addition to '+' operator, the string type supports several
'methods' For example,
String s = "foo";
int len = s.length(); // length method return number of chars (3)
- We saw static methods in the previous lecture, these are essentially
global functions in the C or Scheme sense. The length() method of
String is an 'instance' method. The means it has access to the
data of a particular instance of the String on with it was invoked.
- In general method call syntax is objectvar.methodname(args..);
- There are also static methods of string. For example:
String.valueOf(int i) -- returns String representation of i.
- The general static method call syntax is ClassName.methodName(args...)
- Instance methods are essentially function calls with one implicit
argument: the object instance on which the method is called.
- Strings support other methods
char charAt(int i) -- returns character at position i
String substr(int start, int len) -- returns substring
- String's are immutable, once created they cannot be altered (this
is not true of objects in general.
- It is important to keep the distinction between the Class String
and instances of String (ie "foo").
- String ( and objects in general) are created by calling their
'constructor' routine with the operator 'new'
String s = new String("foo");
- Constructors have the name of the object type (the class). A class
can have multiple constructors with different argument signatures.
- Constructors are always called with 'new';
- Unlike C++, Java has no destructors. Object instances are garbage
collected when no longer references (as in Scheme).
{
String a = new String("foo"); // create new string
String b = a; // init var with existing string
String c = a.concat(b); // concatentate a and b (same as a+b)
int i = c.length(); // i set to 6
String d = c.substring(2); // d set to "ofoo"
boolean e = d.equals("ofoo"); // e set to true
}
Defining Classes
- String is a built-in object type (this lets Java use '+' for concat)
- Java (and other OO languages) allows programmers to create user defined
classes, extending the type system with new object types.
- Defining new classes is a matter of defining the data each instance
maintains, and the set of methods that manipulate that data.
- As a running example, we will develop a class to represent Vect2D
numbers z=a+bi
- Classes are defined with keyword 'class'. The source for a class must
be in a .java file of the same name (case sensitive)
class Vect2D {
}
- The data carried by each class instance is defined as instance variables.
class Vect2D {
double x = 0.0; // x component (initialized to 0)
double y = 0.0; // y component (initialized to 0)
}
- Instance vars can be initialized in their definition as well as
their constructor.
- Constructor routines have the same name as the class and return no type
(not even void).
class Vect2D {
// Declare instance vars private, only class methods can access
private double x = 0.0; // x component (initialized to 0)
private double y = 0.0; // y component (initialized to 0)
// Construct Vect2D from x and yinary parts
public Vect2D(double xval, double y){
x = xval; // instance vars are in scope in class methods
this.y = y;
}
}
- The implicit instance argument is bound to the reserved variable 'this'
We could have used this.x instead of x.
- Since data members are private (always good practice), we provide
accessor routines to access them. There is a naming convention:
for variable 'foo' accessor is getFoo()
class Vect2D {
// Declare instance vars private, only class methods can access
private double x = 0.0;
private double y = 0.0;
... Constructors etc....
// Accessors
public double getX(){
return(x);
}
public double getY(){
return(y);
}
}
- We are making Vect2D an immutable type, otherwise we would
supply mutator methods as well (convention setFoo())
- Vect2D should support an absolute value methods (sqrt r2 + i2)
class Vect2D {
// Declare instance vars private, only class methods can access
private double x = 0.0;
private double y = 0.0;
... Constructors, Accessors etc....
// absolute value routine.
public double length(){
return(Math.sqrt((x*x) + (y*y)));
}
}
- Vect2D should support an binary operations add and mult. We have
a choice: make them static binary methods as in
public static Vect2D add(Vect2D a, Vect2D b);
or unary instance methods
public Vect2D add(Vect2D b); // first argument implicit
Binary (static form emphesizes symmetry while unary (instance) form
more flexible due to inheritance. We'll do both here.
class Vect2D {
// Declare instance vars private, only class methods can access
private double x = 0.0; // x part (initialized to 0)
private double y = 0.0; // yinary part
... Constructors, Accessors etc....
// Multiplication by a real (scaling)
public Vect2D scale(double s){
Vect2D result = new Vect2D(); // empty constructor
// Class methods can access instance var of ALL instances
// (assuming it has references in scope).
result.x = (x * s);
result.y = (y * s);
return(result);
}
// Addition
public Vect2D add(Vect2D b){
Vect2D result = new Vect2D(); // empty constructor
// Class methods can access instance var of ALL instances
// (assuming it has references in scope).
result.x = x + b.x;
result.y = this.y + b.y; // to be explicit
return(result);
}
// Addition
public static Vect2D add(Vect2D a, Vect2D b){
Vect2D result = new Vect2D(); // empty constructor
// Class methods can access instance var of ALL instances
// (assuming it has references in scope).
result.x = a.x + b.x; // to be explicit
result.y = a.y + b.y; // to be explicit
return(result);
}
}
- As in above, methods can be overloaded with different argument signatures
Design with classes: Typical class types
- As we can see, developing classes and programming methods is pretty
straightforward. The challanging part is deciding which classes
to create and what methods to support.
- Some common catagories of classes in typical programs
Database -- classes that essentially represent database objects, common
in business ( or psuedo-business apps). Ex
Employee, Manager, Order, RushOrder, InventoryItem, ...
Many programs are consist essentially of DB manipulation,
always ask 'why not use a real DB?'
Algebraic -- classes represent algebraic types (eg Complex)
Container -- classes to hold collections of objects: lists, hashtables, etc.
I/O and Network -- mediate access to external data streams.
GUI objects -- Buttons, frames, text areas, etc.
Graphics -- Fonts, images, brushes, etc.
Callbacks -- a technical use of objects to pass methods around as arguments
and store as data (methods are not first-class objects in
Java, they need a supporting instance).
Recitation:
Review:
public,private,protected keywords for methods,variables
static, final keywords
initialization of instance vars (order of initialization)
strange, but useful Java syntax involving
new in argument foo(new String("bar"));
new in expr (new String("foo")).length
return value as expr foo(b).bar(c);
mutators
implications of lack of destructor (resource cleanup).
java.util.* classes and on-line doc.