Classes and Objects II
- Contents
- Aggregation
- Returning References to Private Fields
- The
null
Reference - The
this
Reference - Enumerated Types
- Garbage Collection
- The
finalize
Method - Class Collaboration
- CRC Cards
Aggregation
Creating an instance of one class as a reference in another class is call object aggregation.
Aggregation creates a “has-a” relationship between objects.
Book example:
Aggregation in UML Diagrams
Example code:
public class Program { public static void main(final String[] args) { final Physique physique = new Physique(10, 20); final Person person = new Person(physique); System.out.println(person); } } final class Person { private final Physique physique; public Person(final Physique physique) { this.physique = physique; } @Override public String toString() { return "A person with physique: " + this.physique; } } final class Physique { private final int height; private final int weight; public Physique(final int height, final int weight) { this.height = height; this.weight = weight; } @Override public String toString() { return "height " + this.height + " weight " + this.weight; } }
Returning References to Private Fields
Avoid returning references to mutable, private fields.
Returning references to private fields allows any object that receives the reference to modify the variable.
Example code:
public class Program { public static void main(final String[] args) { final Person person = new Person(10, 20); final Physique physique = person.getPhysique(); System.out.println(person); // Note the height field can be modified // without notifying the Person object. physique.setHeight(15); System.out.println(person); } } final class Person { private final Physique physique; public Person(final int height, final int weight) { this.physique = new Physique(height, weight); } // Note this method returns a reference // to a mutable, private field. public Physique getPhysique() { return this.physique; } @Override public String toString() { return "A person with physique: " + this.physique; } } class Physique { private int height; private int weight; public Physique(final int height, final int weight) { this.height = height; this.weight = weight; } public void setHeight(final int height) { this.height = height; } @Override public String toString() { return "height " + this.height + " weight " + this.weight; } }
The null
Reference
A
null
reference is a reference that is not associated with any object.If a reference is
null
then no operations can be performed on it.References can be tested to see if they are
null
prior using them.Book example:
Example code:
public class Program { public static void main(final String[] args) { final Person personA = new Person(new Physique(10, 20)); System.out.println(personA); // intentionally pass in a null referenced parameter. final Person personB = new Person(null); System.out.println(personB); } } class Person { private Physique physique; public Person(final Physique physique) { // Check for a null reference and // act accordingly. if (physique == null) this.physique = new Physique(0, 0); else this.physique = physique; } @Override public String toString() { return "A person with physique: " + this.physique; } } final class Physique { private final int height; private final int weight; public Physique(final int height, final int weight) { this.height = height; this.weight = weight; } @Override public String toString() { return "height " + this.height + " weight " + this.weight; } }
The this
Reference
The
this
reference is a name that an object can use to refer to itself.The
this
reference can be used to overcome shadowing and allow a parameter to have the same name as an instance field. Shadowing is to be avoided in instance methods.-
The
this
reference can be used as a method to call a constructor from another constructor.- Elaborate constructor chaining can be created using this technique.
- Invoking
this
as a method is allowed as only the first statement of a constructor.
-
Example code:
public class Program { public static void main(final String[] args) { final Person person = new Person(10, 20); System.out.println(person); } } class Person { private final Physique physique; // This constructor calls another constructor // with the 'this' reference. Note the call to the // other constructor must be the first statement. public Person(final int height, int weight) { this(new Physique(height, weight)); } public Person(final Physique physique) { this.physique = physique; } @Override public String toString() { return "A person with physique: " + this.physique; } } final class Physique { private final int height; private final int weight; public Physique(final int height, final int weight) { this.height = height; this.weight = weight; } @Override public String toString() { return "height " + this.height + " weight " + this.weight; } }
Enumerated Types
Introduction
Known as an
enum
, requires declaration and definition like a class.An
enum
is a specialized class.In the following example, the
gender
variable holds the address of theGender.Female
object.Example code:
public class Program { public static void main(final String[] args) { final Gender gender = Gender.Female; final Person person = new Person(10, gender); System.out.println(person); } } enum Gender { Confidential, Male, Female; } final class Person { private final int height; private final Gender gender; public Person(final int height, final Gender gender) { this.height = height; this.gender = gender; } @Override public String toString() { return "A person with gender " + this.gender + " and height " + this.height; } }
Methods
The
toString
method returns the name of the enumerated value.The
ordinal
method returns the zero-based position of the constant in the enumeration.The
equals
method accepts an object as an argument and returnstrue
if the argument is equal to the calling enumerated constant.The
compareTo
method accepts an object as an argument and returns a negative integer if the calling constant’s ordinal is less than the argument’s ordinal, a positive integer if the calling constant’s ordinal is greater than the argument’s ordinal, and zero if the calling constant’s ordinal is equal to the argument’s ordinal.Example:
Example code:
public class Program { public static void main(final String[] args) { final Gender female = Gender.Female; System.out.println( "female.ordinal() = " + female.ordinal()); System.out.println( "Gender.Male.ordinal() = " + Gender.Male.ordinal()); System.out.println( female.compareTo(Gender.Male) > 0 ? "Female is higher ordinal." : "Male is higher ordinal."); } } enum Gender { Confidential, Male, Female; }
Switching
Java allows us to test an enumerated value with a
switch
statement.Example code:
public class Program { public static void main(final String[] args) { final Person person = new Person(10, Gender.Female); System.out.println(person); } } enum Gender { Confidential, Male, Female; } class Person { private int height; private Gender gender; public Person(final int height, final Gender gender) { this.height = height; this.gender = gender; } @Override public String toString() { // Careful: the gender can be null. if (this.gender != null) { switch (this.gender) { case Female: return "Girl: " + this.height; case Male: return "Boy: " + this.height; case Confidential: return "N/A: " + this.height; } } return super.toString(); } }
Garbage Collection
When objects are no longer needed, they are destroyed to free memory they consume.
Java handles all low-level memory operations.
When all references for an object are set to
null
, Java will reclaim memory for that reference.The Java Virtual Machine (JVM) has a background process that reclaims memory from unreferenced objects.
This background process is known as the Garbage Collector (GC).
The following code sets
account1
andaccount2
to the same object.BankAccount account1 = new BankAccount(500, 0); BankAccount account2 = account1;
These references are for the same instance of the
BankAccount
class.The following code releases one reference; the GC will not reclaim memory at this point.
account1 = null
The following code releases the last reference to the object.
account2 = null
The GC will reclaim memory for this instance sometime later from its background process.
The finalize
Method
If a method with the following signature is included in a class, this method will run just prior to the garbage collector’s reclaiming its memory.
public void finalize() {...}
The garbage collector is a background thread that runs periodically.
It cannot be determined when the
finalize
method will actually be run.Finalizers are unpredictable, often dangerous, and generally unnecessary. The use of finalizers can cause erratic behavior, poor performance, and portability problems.
Nothing time-critical should be done by a finalizer.
Do not depend on a finalizer to update critical persistent state.
Provide an explicit termination method for a class that manages objects that encapsulate resources that require termination. The
close
method onInputStream
andOutputStream
is such an example.Two legitimate use of finalizer:
Use a finalizer as a "safety net" in case the owner of an object forgets to call the explicit termination method. It’s better to free the critical resource late than never. For example,
InputStream
andOutputStream
have finalizers that call theirclose
methods.Use finalizers to terminate non-critical native resources.
-
Use
try-finally
blocks around methods that provide explicit termination methods.import java.io.PrintStream; public class Program { public static void main(final String[] args) throws Exception { final String text = "BAD-FORMAT"; PrintStream out = new PrintStream("output.txt"); try { out.println(Integer.parse(text)); } finally { out.close(); System.out.println("Resource closed."); } } }
Class Collaboration
Collaboration — two classes interact with each other.
When a
StockPurchase
class collaborates with aStock
class, aStockPurchase
object may create and manipulate aStock
object.Example:
CRC Cards
Class Responsibilities and Collaborations (CRC) cards are useful for determining and documenting a class’s responsibilities.
- The things a class is responsible for knowing
- The actions a class is responsible for doing
CRC Card Layout
From Wikipedia.org
CRC cards are a brainstorming tool used in the design of object-oriented software.
They are typically used when first determining which classes are needed and how they will interact.
CRC cards are usually created from index cards on which are written:
The class name
The Super- and Sub-classes (if applicable)
The responsibilities of the class
The names of other classes with which the class will collaborate to fulfill its responsibilities
The author