slanted W3C logo

Day 20 — Aggregation 2

In today's lecture we look at aggregation and how it affects the use and copying of objects.

The material covered reflects Chapter 8 of the 3rd Edition of the textbook (there are significant differences between the 2nd and 3rd Editions in Section 8.2).

Call number of textbook on reserve in Steacie: PCOP.2629STEACIE

Copying Objects: Aliasing

Sometimes a client will want to create a copy of an object. The cleanest way to copy an object is to use what is called a copy constructor, but many existing classes do not provide them. In these cases, the client has to do some extra work.

The simplest form of copying an object is to create an alias:

Investment inv = new Investment(new Stock("HR.A"),
                                10, 2.00);
Investment alias = inv;

Copying Objects: Aliasing

Investment inv = new Investment(new Stock("HR.A"),
                                10, 2.00);
Investment alias = inv;
 
inv ⇒ 400
alias ⇒ 400
 
  |
400 Investment object
stock ⇒   500
  |
500 Stock object
 

When you create an alias, you are referring to an existing object; inv and alias both refer to the Investment object at address 400.

Copying Objects: Aliasing

How can you tell if a copy is an alias? Use ==.

boolean isAlias = (inv == alias);

This also applies to references returned by accessors.

Copying Objects: Shallow Copy

A shallow copy of an object creates a new object with attributes that are identical to the original object. If the original object is an aggregation, then the copied object aggregates the same objects as the original.

Investment inv = new Investment(new Stock("HR.A"),
                                10, 2.00);
Investment shallow =
    new Investment(inv.getStock(),
                   inv.getQty(),
                   inv.getBookValue());

Copying Objects: Shallow Copy

Investment inv = new Investment(new Stock("HR.A"),
                                10, 2.00);
Investment shallow =
    new Investment(inv.getStock(),
                   inv.getQty(),
                   inv.getBookValue());
 
inv ⇒ 400
shallow ⇒ 500
 
  |
400 Investment object
stock ⇒   600
  |
500 Investment object
stock ⇒   600
  |
600 Stock object
 

When you create a shallow copy, you create a new object but that object contains aliases to existing objects.

Copying Objects: Shallow Copy

How can the client show that shallow is (probably) a shallow copy of inv? Check to see if object references returned by accessors are aliases.

boolean isShallow = (inv.getStock() == shallow.getStock());

In the above code fragment isShallow is true indicating that stock aggregated by inv is the same object as the stock aggregated by shallow.

Note that if getStock returns a copy of a stock then there is no way for the client to make a shallow copy of inv in this example.

Copying Objects: Shallow Copy

Copy constructors can also create shallow copies; you have to read the API of the class you are copying.

Investment(Investment investment)
   Construct a (shallow) copy of the passed Investment.

Copying Objects: Deep Copy

A deep copy of an object creates a new object with attributes that are copies of those of the original object. If the original object is an aggregation, then the copied object aggregates different objects as the original.

Investment inv = new Investment(new Stock("HR.A"),
                                10, 2.00);

// create a deep copy of the aggregated Stock           
Stock s = new Stock(inv.getStock().getSymbol());

// create a deep copy of the Investment
Investment deep =  new Investment(s,
                                  inv.getQty(),
                                  inv.getBookValue());

Copying Objects: Deep Copy

Investment inv = new Investment(new Stock("HR.A"),
                                10, 2.00);

// create a deep copy of the aggregated Stock           
Stock s = new Stock(inv.getStock().getSymbol());

// create a deep copy of the Investment
Investment deep =  new Investment(s,
                                  inv.getQty(),
                                  inv.getBookValue());
 
inv ⇒ 400
s ⇒ 700
deep ⇒ 500
 
  |
400 Investment object
stock ⇒   600
  |
500 Investment object
stock ⇒   700
  |
600 Stock object
  |
700 Stock object
 

When you create a deep copy, you create a new object and that object contains references to newly created objects.

Copying Objects: Deep Copy

How can the client show that deep is (probably) a deep copy of inv? Check to see if object references returned by accessors are not aliases.

boolean isDeep = (inv.getStock() != deep.getStock());

In the above code fragment isDeep is true indicating that stock aggregated by inv is a different object from the stock aggregated by deep.

8.2 Collections

A collection is an object that groups multiple object references into a single unit. You can think of a collection as representing a container for objects where each object is usually referred to as an element.

Remember that there are significant differences between the 2nd and 3rd Editions of the textbook in Section 8.2.

Call number of textbook on reserve in Steacie: PCOP.2629STEACIE

Collections

Because a collection groups multiple object references, it is an aggregation. Typically, a collection aggregates elements that form a natural group. For example:

Collection Of Represents
at most 23 hockey players National Hockey League team roster
at most 7 playing cards Texas Holdem poker hand
words dictionary
books library

Creating a Collection

Notice that some collections have a natural maximum capacity, whereas the size of other collections naturally grows and shrinks.

In the case of a collection with a known maximum capacity, it is possible to allocate enough memory to store the collection when the collection is created; this is called static allocation (where static means unchanging and is not related to the Java keyword).

In the case where the size of the collection can grow and shrink, memory is allocated as it is needed, which is called dynamic allocation.

Statically Allocated Collection

The Portfolio class is an example of a statically allocated collection. It represents a collection of Investment objects.


// no name portfolio with capacity 100
Portfolio pf = new Portfolio();
      
// named portfolio with capacity 50
Portfolio myPf = new Portfolio("My Retirement Fund", 50);

Note that the capacity of a collection is different than its size. The capacity of a portfolio is the maximum number of investments that it can hold. The size of a portfolio is the actual number of investments in the portfolio.

Dynamically Allocated Collections

GlobalCredit is an example of a dynamically allocated collection. It represents a collection of credit cards (presumably distributed by a bank).


// an empty collection of credit cards
GlobalCredit cards = new GlobalCredit();

Some collections have constructors where the client can specify an initial capacity of the collection, but GlobalCredit does not have such a constructor.