Important note: This question concerns optimising a piece of software for memory-efficiency. The purpose here, as usual, is to expose you to more of Java, and in particular to get you to think about heap memory usage. In general, it is not a good idea to speculatively optimise software, either for performance or memory-efficiency. Such optimisations should be guided by profiling: testing a piece of software on real data to work out where the efficiency bottlenecks are. Optimisations make code harder to understand and maintain. So, while we will explore an optimisation in this questions, the message is not that you should apply this kind of optimisation by default.
Consider the following Point class, which is very similar to the Point
class you created and worked with in question 0f05:
Observe that instances of Point are immutable. We sometimes call immutable objects value objects because they be used in a similar way
to primitive values: because they cannot change, they do not suffer from problems of aliasing that are relevant for mutable objects.
Suppose an application is likely to create a vast number of Point objects, but that many of these objects are likely to
be identical. For efficient memory usage, in this case it might be preferable to keep a pool of points that have already been
created, and when asked for a new point to return a matching point in the pool, if one exists.
Your task is to implement this scenario. Make the constructor of Point private, so that clients cannot create points directly.
In Point, declare a static method, makePoint, with the following signature:
public static Point makePoint(int x, int y, int z);
This static method will be the single place where points can be created; such a method is called a factory method.
The aim of makePoint is to cache all points that have been previously created. If makePoint is invoked
with the coordinates of a point that already exists, a reference to the existing point will be returned. This can save memory
by avoiding the client holding references to many identical points stored in distinct objects.
To achieve the desired effect of makePoint, equip the Point with a private static field that maps points to
points:
private static Map<Point, Point> pool = new HashMap<Point, Point>();
This makes use of the Map interface from java.util, and one of its implementing classes, HashMap.
Somewhat strangely, we are going to use pool to map a Point object reference to itself! You may ask, why
can't we just use a Set? The reason is that we will wish to ask: "does the pool contain a Point that
is equal to some new Point?", and if the answer is "yes", we wish to get the original Point contained in the pool. While a Set would allow us to ask the question, it does not provide an efficient way for us to get at the reference to the original Point. (We could iterate through the whole set until we find the reference of interest, but this would be highly inefficient.)
Your implementation of makePoint should do the following:
-
Construct a new
Pointwith the given coordinates, and store the result in a reference variable (sayp) -
Test whether
poolmapspto some point. This can be ascertained by asking whetherpool.get(p)isnull -
If
pooldoes mappto some point thenmakePointshould return thePointto whichpis mapped. As a result, the new object to whichppoints becomes unreachable, and will be garbage-collected -
If
pooldoes not mappto some point thenmakePointshould addpto the pool by using theput(Point, Point)method ofMapto mappto itself. After this,pshould be returned
To convince yourself that your implementation is indeed saving memory, write two main methods. Each should create a list of points, and add 10 identical points to the list. The first program should use the original Point class, creating 10 distinct points. The second should use the new Point class with its makePoint factory method. In the first instance you should write a method that checks whether the references in your list are all different. In the second case you should write a method that checks whether the references in your list are all the same.