You are on page 1of 15

Further

Object Oriented Programming


“FOOP”
Introduction
and Basic Aspects of OOP
ECS658U
Matthew Huntbach
matthew.huntbach@qmul.ac.uk

Part 4
1
Binary Search
• Here is the method contains in IntSet if the method add is
implemented in a way that keeps the array in numerical order:
public boolean contains(int n) {
int first=0;
int last=array.length;
while(last>first) {
int mid = (first+last)/2;
if(array[mid]==n)
return true;
if(array[mid]<n)
first=mid+1;
else
last=mid;
}
return false;
}

2
Efficiency Issues
• As mentioned previously, an important aspect of programming is
being efficient
• This becomes more of an issue with large amounts of data
• In the example of the remove method, the inefficient version
could take up to twice as long to work as the efficient version
• Consider in this case the difference between going through an
array element by element and going through it by continuously
dividing the section being searched into half
• The maximum number of checks of an array of length m is log2m
which is the value v where 2v is m
• So for an array of length 1024 it would be a maximum of 10
checks rather than 1024
• Checking for efficiency requires using much more data than you
can just type in
• Code to produce large quantities of random data for efficiency
checking can be an important issue to consider
3
Recursion
Here is how contains with binary search could be implemented
recursively:

public boolean contains(int n) {


return between(n,0,array.length);
}

private boolean between(int n, int from, int to) {


if(from>=to)
return false;
int mid = (from+to)/2;
  if(array[mid]==n)
      return true;
  if(array[mid]<n)
      return between(n,array,mid+1,to);
  else
      return between(n,from,mid);
}
4
Assistant Methods in Objects
• A method declared as private is for use only inside other
methods in the class it is in
• It is important to declare a method as private if it is introduced for
this reason rather than because it is a required part of WHAT
objects of that class do
• Recursion does not improve efficiency, but skilled programmers
often find it easy to think in terms of recursion and so write code
recursively first, maybe after that turning it into a loop version
• An assistant method is needed if recursion requires some extra
values, as is the case here
• Here a method call between(n,from,to) returns true if n is in the
array referred to by array in the section from position from up to
but not including position to, otherwise it returns false, under the
assumption that the array is sorted
• Return true if it is in the middle position, otherwise search in the
section up to the middle or in the section after the middle

5
Generalised Ordering
• For simplicity, the example code for a set where elements are
stored in order so that contains can be done efficiently went back
to code that only represents a set of integers
• This code has the test array[mid]<n as part of it
• In Java, the symbol < can only be used to compare numerical
values, so it can’t be used in generalised code
• The test array[mid].compareTo(n)<0 is the equivalent in
generalised code
• However, while array[mid].equals(n) could be used for objects of
any type, it is not the case that object of every class have the
method compareTo that can be called on them
• If a class does have a compareTo method, that is called the
natural order of objects of that class
• We can write generalised code for a set of any type of object
which does have the method compareTo, we will look at that later

6
Overriding Symbols
• In some other programming languages, it is possible to write a
method in a class which means obj1<obj2 could work where obj1
and obj2 are variables of any class type
• For example, in Python the test obj1<obj2 turns into a method
call obj1.__lt__(obj2) so providing a method __lt__ in a class in
effect overrides the symbol <
• An advantage of this is that it makes the code look simpler
• A disadvantage of this is that as obj1<obj2 results in a method
call, you cannot be sure how efficient code is, as it could involve
some calculation that takes a long time
• Similarly, in Java, obj1==obj2 does not result in a method call, so
you know it is done in one step, whereas in Python, obj1==obj2
is equivalent to the method call obj1.equals(obj2) in Java
• The language C++ is similar to Java, but does allow overriding
of symbols

7
Overriding toString
• Although in general Java does not allow symbols to be
overridden by methods, there is one case in Java it does
• It is the symbol +
• In Java, v1+v2 results in toString being called on the object
referred to by v1 and v2 if they are not numerical variables
• If one is numerical, but the other is not, the String equivalent of
the numerical value is joined to the result of calling toString on
the other to produce a new String
• All objects have a method toString, because it is inherited from
Object, but it is always a good idea to write your own toString
method in any class because if toString is not overridden what it
returns does not give a good indication of the object it is called
on
• As explained previously, one reason for being able to print
something that gives a good representation of an object is to
assist in development, helping find where errors occur
8
Overriding toString and equals
• This code would override toString in the Set class given:
 public String toString() {
  return Arrays.toString(array);
 }
• The method toString it uses is not the standard toString method,
but a static method in the class Arrays that Java provides
• It shows another reason why it would be best to store elements
in a sorted order, because otherwise two objects that are meant
to represent the same set will have a different toString result
• Another issue is overriding equals. All classes have the method
equals as it is inherited from Object, but if it is not overridden
set1.equals(set2) will return true only if set1 and set2 refer to the
same object
• We would want set1.equals(set2) to return true if they refer to
separate objects that contain the same contents

9
String method substring
• This might be better code to override toString in the Set class
given:
 public String toString()
 {
  String astr = Arrays.toString(array);
String instr = astr.substring(1,astr.length()-1);
  return "{"+instr+"}";
 }
• The idea here is that the String to represent a Set should not be
the same as one to represent an array
• So where the previous version would return [3, 7, 8, 9] this will
return {3, 7, 8, 9}
• Note the way it works to remove the [ and ] and replace them by
{ and }

10
Constructive and Destructive Methods
• Another important basic thing to understand in Object Oriented
Programming is the distinction between methods that work by
changing objects, and methods that work by creating and
returning a new object representing the change
• A method which works by creating and returning a new object
representing a change is called a constructive method
• A method which changes an object, either the one it is called on,
or one passed to it is called a destructive method
• With a destructive method, when an object is changed, all
variables that refer to that object have what they refer to
changed
• In the example given, the methods work destructively, so a call
set.add(val) changes the actual object that set refers to, you don’t
assign set to what it returns
• Note that substring works constructively on a String

11
Constructive Version of add
public Set<E> add(E n) {
if(!this.contains(n)) {
E[] array1 = (E[]) (new Object[array.length+1]);
for(int i=0; i<array.length; i++)
array1[i]=array[i];
array1[i]=n;
return new Set<E>(array1);
}
return new Set<E>(array);
}

In this case, it always returns a new object, even if the method does not
cause a change to the set. The reason for this is that otherwise you
would not know whether set2=set1.add(val) results in set2 referring to
what set1 refers to or to a separate new object

12
Private Constructor
• The constructive version of add needs another constructor that has
to be added to the class:
private Set<E>(E[] array1) {
array = array1;
}
• As explained previously, a public constructor for a Set which takes an
array as an argument and sets the Set’s array to the same array is
not a good idea, because then other code can change what is in the
array, and that breaks the important principle that an object should
only be changed by methods called on it, or passing it as an
argument to a method
• The point about a private constructor is that it can only be called by
code inside its own class, so it can safely take arguments that would
cause problems if the constructor could be called anywhere

13
The Set code was to illustrate concepts
• We don’t really need to write code that implements a set, because
Java provides built-in code which does that
• Java’s standard collection code is mutable, meaning objects work by
having methods that change them rather than methods that create
and return new collection objects
• The class IntSet and then Set were given here not because you
would need to write this code professionally, but because it works to
give examples of various aspects of OOP that apply more generally
to writing code
• Implementing Set in a way that means any change to the set has to
be done by completely replacing its internal data by new data is very
inefficient, and is not how Java’s own code does it
• You will have seen in the Algorithms and Data Structure module
better ways of implementing collections, we will give further
consideration of how it is done in Java’s own code later

14
OOP in General
• When Object Oriented Programming is first taught, it tends to be
illustrated by objects which represent things in the real world where
you are writing code to model them
• In that case, the methods called on objects will represent real world
actions that the things in the real world can do, or have done to them
• Good representation then means you should avoid having methods,
or ways of changing data inside objects that would change them in a
way that the real world things they represent could not do
• As we have shown here, classes can also be used to implement
objects which are needed for more abstract aspects of coding
• The main point is to clearly divide code into separate parts, given by
classes, with a clear definition of how objects interact
• Limiting the way objects can interact makes code easier to
understand, and easier to modify

15

You might also like