University of Oxford |
|
Computing Services |
|
Teaching a Course on Understanding Java |
|
Author: Barry Cornelius Date: 24th January 2000 |
The main aim of this paper is to explain the rationale behind the design of a course that is an introduction to programming using Java. One of the key features of this course is the early introduction of interfaces. The paper explains why it is appropriate to do this. The paper also points out some of the deficiencies in the design of classes that are made by textbooks that are targetted at this kind of course.
During the last 25 years, I've been involved on a number of occasions with switching the first programming language.
University of Hull Algol 60 Pascal University of Durham Pascal Modula-2 University of Durham Modula-2 JavaEvery time you find yourself with a lot of new ideas to teach. And I find it exciting to sit down and think about what order to teach the various ideas.
Using Pascal/Modula-2, the topics that I have taught included:
terminal I/O expressions if statement for statement case statement while statement arrays procedures and functions recursion records pointers linked lists stacks queues trees
When moving to Java, procedures and functions are called methods, and pointers, linked lists, stacks, queues and trees are replaced by other things.
Here is a list of some of the new ideas of Java:
creating an object using an instance method using a class method using the wrapper types (Integer, Double, etc) declaring a class type declaring a method declaration declaring an interface implementing a Core API interface implementing one of your own interfaces implementation inheritance from a Core API class implementation inheritance from one of your own classes creating a window adding buttons to a window using a textfield for input/output providing menus using MVC to design programs using the Collection API: lists, queues, stacks using the Collection API: sets using the Collection API: maps using a throws clause using a try statement declaring an exception class using applets
Those are some of the topics that I teach, but of course there are many more that could be taught. The order in which the parts of Java are taught in this course is given in the Appendix to this paper.
If primitive types have to be taught reasonably early, how do we teach both primitive types and class types? My own view is that they can be taught in the following order:
So, although some may argue that my course is not an object-first course:
So in this course, the following order is used to teach the bread-and-butter topics:
I'm not ashamed that you will find these taught in this order in many books that are teaching a language other than Java.Both Ada and Modula-2 separate out the interface from the implementation:
Ada package specification package body Modula-2 definition module implementation moduleAlthough a similar idea can be achieved in C++, it is not so cleanly done. In Java, interfaces can be used:
Java interface declaration class declaration
public interface Date; { public int getDay(); ... public void setDay(int pDay); ... } public class DateImpl implements Date { private int iYear; private int iMonth; private int iDay; ... public int getDay() { return iDay; } ... public void setDay(final int pDay) { iDay = pDay; } ... }
The lectures stress that code should be written in terms of the interface and that the name of the class should only be used when you want to create an object (of the class that implements the interface):
Date tTodaysDate = new DateImpl(2000, 1, 24); ... private static boolean iIsLeap(final Date pDate) { final int tYear = pDate.getYear(); return (tYear%400==0) || (tYear%4==0 && tYear%100!=0); }
'Design Patterns:
Elements of Reusable Object-Oriented Software'
Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides
‘This ... leads to the following principle of reusable object-oriented design:
Program to an interface, not an implementation.
Don't declare variables to be instances of particular concrete classes.
Instead, commit only to an interface defined by
an abstract class
[or an interface in Java].
You will find this to be a common theme
of the design patterns in this book.’
Another book that covers similar material is 'Patterns in Java: Volume 1' by Mark Grand.
‘One of the great qualities of object-oriented development is that you can vary the interfaces of classes independent of the implementation. Much of the power of object development comes from this property. However, few people make good use of it. Programming languages use a single construct, the class, which contains both interface and implementation. When you subclass, you inherit both. Using the interface as a separate construct is rarely used, which is a shame.’
'ChiMu OO and Java Development: Guidelines and Resources'
ChiMu Corporation
‘Use interfaces as the glue throughout your code instead of classes:
define interfaces to describe the exterior of objects
(i.e., their Type)
and type all variables, parameters, and return values to interfaces.
The most important reason to do this is
that interfaces focus on the client's needs:
interfaces define what functionality a client will receive from an Object
without coupling the client to the Object's implementation.
This is one of the core concepts to OO.’
http://www.chimu.com/publications/javaStandards/
In an informal analysis of when specific aspects of Java are taught by various books, I obtained the following results. When a result appears as n:p, n gives the page number and p gives the page number expressed as a percentage. So the percentage figure gives a measure of how far through the book the aspect is taught.
Arnow Bishop Deitel Garside Horstmann Koffman Lewis Smith Cornelius How many pages are in the main part of the text? How many in all? 725,805 479,508 1228,1344 609,660 569,624 683,824 559,857 433,474 ?470,?500 When is the user-declared class introduced? 90:12 80:17 326:27 170:28 324:57 56:08 140:25 66:15 206:44 When are interfaces introduced? 659:91 269:56 427:35 347:57 no 440:64 338:60 269:62 223:47
When teaching interfaces and classes, I stress that it is important that each interface-class has:
Most books do not provide each class with the ability to find out whether two objects of the class have the same value.
public boolean equals(Date pDate) { return iYear==pDate.iYear && iMonth==pDate.iMonth && iDay==pDate.iDay; }If a client attempts to use objects of this class with objects of the Collections API (or Hashtable or Vector), they are in for a shock. None of the following methods will work with that declaration of equals:
Hashtable | contains, containsKey, get, put, remove |
Vector | contains, indexOf |
List | contains, remove, indexOf |
Map | containsKey, containsValue, get, put, remove |
Set | add, contains, remove |
Instead, you need to teach that for the equals method to be useful it needs to have a parameter of type Object. For example, if we are providing an interface called Date and a class called DateImpl, we could declare the following:
public boolean equals(final Object pObject) { if ( ! (pObject instanceof DateImpl) ) { return false; } return iYear==((DateImpl)pObject).iYear && iMonth==((DateImpl)pObject).iMonth && iDay==((DateImpl)pObject).iDay; }
If you declare equals properly, you need also to declare hashCode. There are warnings about this in the documentation of some of these classes. For example, the WWW pages that document java.util.Hashtable states that ‘to successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.’
public int hashCode() { return iYear*416 + iMonth*32 + iDay; }
The informal analysis of when specific aspects of Java are taught by various books gave the following results:
Arnow Bishop Deitel Garside Horstmann Koffman Lewis Smith Cornelius Does the book suggest that equals always be declared? lost no no no 339:60 no lost lost 219:47 Does the book teach the proper declaration of equals? lost no no no 340:60 no no wrong 221:47 Does the book teach the proper declaration of hashCode? no no no no no no no 311:72 223:47
Few books explain that it is desirable for a class to provide a cloning operation.
Date tBirthDate = new DateImpl(2000, 1, 24); Person tSomePerson = new PersonImpl("Joe", tBirthDate);Do we share?
public class PersonImpl { private String iName; private Date iDateOfBirth; public PersonImpl(final String pName, final Date pDateOfBirth) { iName = pName; iDateOfBirth = pDateOfBirth; // share ...Or do we clone?
iDateOfBirth = new DateImpl(pDateOfBirth); // cloneNote that you need not do this copying if the objects of the class (in this case, the class DateImpl) are immutable.
It is best to provide a method called clone as this can be used when inheritance is involved. However, getting the code of a clone method completely right is difficult. See the article by Bill Venners at http://www.artima.com/innerjava/webuscript/cloning.html
Because it is hard to get right, it is also difficult to teach. Instead, I cheat by just providing a constructor that can be used for cloning:
public DateImpl(final Date pDate) { iYear = pDate.getYear(); iMonth = pDate.getMonth(); iDay = pDate.getDay(); }
public interface Comparable { public int compareTo(Object pObject); }
In order for Date and DateImpl to do this, we need to change the header of the interface Date to be:
public interface Date extends Comparableand to add the following declaration to the class declaration for DateImpl:
public int compareTo(final Object pObject) { DateImpl tDateImpl = (DateImpl)pObject; int tResult = iYear - tDateImpl.iYear; if (tResult==0) { tResult = iMonth - tDateImpl.iMonth; if (tResult==0) { tResult = iDay - tDateImpl.iDay; } } return tResult; }
The Comparable interface became part of Java when Java 2 was released in December 1998. Although most of the books that teach Java as a first language were prepared before then, a few have since been updated for Java 2. None of the ones that I've seen discuss the possibility of a class implementing the Comparable interface.
I've nicked the phrase minimal public interface from a book called 'Object-Oriented Design Heuristics' by Arthur Riel. He says: ‘If the classes that a developer designs and implements are to be reused by other developers in other applications, it is often useful to provide a common minimal public interface. This minimal public interface consists of functionality that can be reasonably expected from each and every class.’
Bill Venners has also written an article on the topic of minimal public interfaces. It is entitled 'The canonical object idiom'. You will find it at http://www.javaworld.com/javaworld/jw-10-1998/jw-10-techniques.html
The previous sections of this paper have described the contents of the first 20 lectures. This is a turning point in the course. Although there are a few important aspects of the Java language that are still to come, most of the important ones have now been introduced. The remaining lectures of the course are mainly concerned with introducing two important APIs: the Swing API and the Collections API.
Although both of these APIs came into being when Java 2 was released, they are both considered by Sun to be part of the Core APIs of Java.
One of the main aims of the second half of the course is to become familiar with these two APIs. They are both quite large: the course's aim is to introduce the basic ideas giving the students sufficient knowledge to look at the other parts of the API on their own.
Note the emphasis in this part of the course is on using the code of existing libraries: by taking a ride on the work of others, Java gives even the beginner the possibility of easily building reasonably powerful pieces of code.
The course looks at the Swing API in two takes. In the first take, the students are introduced to the following ideas:
In later lectures, the classes JMenuBox, JMenu and JMenuItem are introduced. These three classes are needed to build a menu system. Because JMenuItems are another form of button, responding to a click of a menu item can be handled in a similar way to that for buttons (which were discussed in earlier lectures).
The Collections API provides a useful set of interfaces and classes that can be used for building data structures that represent collections of data. The emphasis in this course is on how to make effective use of this API rather than on how to implement the various data structures.
The course describes and explains the differences between the capabilities of the three main interfaces called List, Set and Map (and subinterfaces called SortedSet and SortedMap), and the six classes called ArrayList, LinkedList, HashSet, TreeSet, HashMap and TreeMap. The use of the Iterator interface is also described.
Once again, the stress is to write the code of clients in terms of the interface, only mentioning the name of a class when you want to create a collection object.
Although later lectures show how to implement the List interface by (a) an array and (b) a doubly linked list, this only appears after extensive use in earlier lectures of the List, Set and Map interfaces.
Whilst introducing the Collections API, the course explains and demonstrates the advantages of using the Model-View-Controller pattern to decouple a data structure from any user interface. The simpler form in which the view and the controller are combined (sometimes called Model-UserInterface) is also discussed. By having the class that implements the model derived from java.util.Observable, it is easy to provide multiple views of the model (the class for each view implementing the java.util.Observer interface). These ideas are illustrated by two examples.
The course develops a case study for which different user interfaces are developed and, also, different data structures are used. Both the user interface and the data structure are easily switched because of the use of interfaces and MVC.
Often books on Java teach the following topics in one chapter:
These topics are taught in this order because it seems to be an obvious order: first introduce the advantages of deriving classes from base classes; then explain polymorphism (dynamic binding); the explain that an abstract class is a special form of base class; and finally introduce an interface as a special form of an abstract class. However, a chapter that has these topics introduces a lot of new ideas and explaining them all at once will overload the reader.Although there is some logic to teaching interfaces in this way, it is better to make a clearer separation between implementation inheritance and interfaces. I think it is important to teach interfaces early, and to leave implementation inheritance until later.
Although the lectures on implementation inheritance appears late in this course, some of the basic ideas are introduced in earlier lectures:
Because the full details of implementation inheritance are taught late, the material on applets also appears late. However, because all the ground work has been covered, there is little that needs to be taught about applets: just the role of the init, start, stop and destroy methods.
Some books seem to include exceptions as an afterthought: often the whole topic is taught in the last chapter. As with implementation inheritance, my course gradually introduces the various aspects of exceptions:
Although in Java it can be tempting to overuse exceptions, in this course it is recommended that they are only used for untoward situations. For this reason, the idea of introducing your own exceptions is briefly only mentioned at the end of the course. A good article on the topic is Designing with exceptions by Venners. You will find it at http://www.javaworld.com/javaworld/jw-07-1998/jw-07-techniques.html
Often, books that teach Java provide their own package of classes. One reason for doing this is that it makes it easy to provide a class that facilitates the reading of a value of some primitive type from the keyboard.
Although this approach has its advantages, it is also inconvenient for students:
In this course, the horrors of Java's keyboard input are introduced early:
BufferedReader tKeyboard = new BufferedReader(new InputStreamReader(System.in)); String tHeightString = tKeyboard.readHeightString(); double tHeight = Double.parseDouble(tHeightString);Note the use of both instance methods and class methods and the need to use the wrapper classes of the primitive types.