Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
Introduction to classes and Inheritance plus Exception Handling Introduction to classes and Inheritance plus Exception Handling Summary This week we’ll learn about some of the basics of Java programming. Book reference: Try browsing through Bruce Eckel’s thinking in Java as you try out the exercises set out at the end of these notes. Resources: Some small examples of Java code (available from the COMP229 lectures page)to illustrate some simple inheritance and the basics of error handling. An easy but not OO designed implementation of single pile Nim. We will use this to start a discussion on how to design games using OO. Mixed class exercises These exercises at the end of these notes help you practise writing some Java code and to become familiar with some basic Java features; the practical exercises introduce you to more Java programming and, looking further ahead, introduce some simple GUI exercises. Note that GUI programming will be treated in much greater detail later in the unit, but it’s never too early to start playing with it! Java Classes In Java, Everything is an object. This means that all Java programs are made up of a collection of classes; in particular any data item can only be stored in objects (ie instances) or associated with the whole class (ie is “static”). Unlike languages such as C++ Java does not allow orphaned functions — but only methods as part of some class. As we’ll see, even the “main” function is a method in the class driving the “application”. More about classes A class consists of variables (instance or class), constructors, methods (possibly class). Each of the variables and methods are also modified by its “protection” (eg public, private etc.) In the following code you can see a Template Java Class to illustrate Java’s syntax for setting out a class. public class Classname { // attributes - basic types and other object types private int mLength; private String mName; private MyClass mObject; // optionally one or more constructors public Classname () {}; public Classname (type1 pParam1, type2 pParam2) {}; // methods public rettype procedureName (type3 pParam); // sometimes a main method public static void main (String args[]) { } } The main parts of the class are detailed below: instance variables: each instance or object of the class has its own copy of the data in these fields. class variables: these are “static” variables and there is a single copy of the class shared by all the instances. constructors: these are invoked automatically when a new object is created. There can be several of them and they are distinguished by their signature. methods: these are the functions that act on the data of an object, for example to modify the instance variables. class methods: these are “static” methods and can only modify class variables. A small example As an example of a real class, take a look at the Number class in this week’s code bundle; shown for reference here. public class Number { protected float mMagnitude; // instance variable protected static int mCount = 0; protected static double pi= 3.14;// class variables public Number() { // constructor mMagnitude = 0; mCount = mCount + 1; } public Number(float _num){ // constructor mMagnitude= _num; mCount = mCount + 1; } public float getValue() { return mMagnitude; } // some methods public void setValue(int x) { mMagnitude = x; } public boolean equals(Number x) { if (x != null) { return (this.mMagnitude == x.mMagnitude); } else return false; } public String toString() { return "" + this.mMagnitude; } public static int getNumberOfNumbers() { // class method return mCount; } } As mentioned above the “static” modifier is used to enforce a single instance; this means that static variables don’t belong to an instance or object of a class but rather belong to the class, and therefore are shared amongst all instances; that’s why we call static variables and methods class" variables and class methods. For example mCount is a class variable — this means that although we can declare a seperate number object the mCount is universal to all of the objects. To call a class method, you prefix the method with the name of the class. Have a look in Test.java to see Number.getNumberOfNumbers() . (Given the above explanation, why must it be like this?) Note how the class method and the constructor can refer to the class variable. Java allows several constructors for the same object. The constructors are automatically selected according to their parameter list. Notice that we effectively draw a barrier between the user of the class by making the access to the variables protected . The normal access levels are public , private and protected and “friendly” which is the default. Here’s what they all mean: private means that the variables can only be accessed directly from within the defining class, protected from within subclasses (something for later), public is universally accessible, and “friendly” from within the same package (see below). Observe also the use of the this modifier. We’ll come across more of these handy language constructs when we come to inheritance. We use it as a handy way to refer to the current object; in practice it allows us to use the methods and fields for defining other methods. A small digression Java takes seriously the naming of files in order to locate associated classes, and you’ll need to make sure that you abide by the following conventions. Classes are all defined in a single file with the “.java” extension; the class ClassName must be contained in a file called ClassName.java . A package is a mechanism for organising large programs into logical and manageable units. A package may contain classes, interfaces, or other packages. The package declaration at the top of any class file corresponds exactly to a portion of the directory structure. The classes in this week’s bundle contain a number of folders, each one is a package containing a number of associated .java files. Keep in mind that when you create a package then you are implicitly specifying a directory structure. The package therefore must reside in the directory indicated by the name of the package (which must be a directory available to the Java Interpreter — i.e. something that Java can search as it executes). Packages also have an impact on access. As mentioned above a protected or friendly method or variable is available to all classes within the same package, but not outside. Programming with Objects As with C++ when we create an object we must use the “new” construct, as in Number myNum = new Number(); At this command the following occurs: A block of memory in the heap is allocated — here the values of the object’s field’s can be stored. The object is initialised by calling one of the class’ constructors. Something special happens for class variables an object is created (essentially a single Class object is created –but only once– the first time an object is created. (Details of this are out of the scope of the course.) Notice that the above example of a constructor does not have an argument; Number also has another distinct constructor which can be distinguished by the compiler using the parameter list (Number(float num) takes a single input). This means that myNum = new Number(); calls the original constructor which had no parameters, but that myOtherNum = new Number(6); calls the extra constructor because its parameter list matches the new constructor. And finally a word about the final keyword. This is Java’s syntax for telling the compiler that a piece of data (say) is constant. So if we say final int ii = 11; it means that ii cannot change. (It’s also possible to have final methods and even final classes. If methods are declared final in a class then they can’t be overridden, if a class is final then it can’t be extended at all.) A note about primitive types and basic syntax In spite of “everything being an object”, Java does support all the standard primitive types: boolean, byte, short, int, double char. Moreover arithmetic is also supported, and the same notation and many of the standard syntax (e.g. assignments, control structures). A really good comprehensive list of these familiar features can be found by following the trail in the Sun Java tutorials: , or look in Jia, pages 76 & 87. A small Java application Have a look at Test.java in the Week 2 code bundle which demonstrates the use of Number inside of a small application. Notice that Test.java is in the same package as the Number.java file, but no “include” statement was needed for the compiler to be able to find the definitions. This is because the naming scheme for the classes and packages have been designed to avoid that inconvenience! (Recall comments about packages above.) As mentioned above, in any application we need a single method “main” to drive it; this appears as one of the methods in the class Test , and it is static because there can only be one main in any application. Notice how the new instances of the Number are initialised with or without parameters. Some other Java features We’ll discuss some of the other examples in Test.java below. For now let’s have another look at some other features and Java idiosyncracies, beginning with variables. Variables and pointers In C++ we have to be very careful about decorating the code with referencing and dereferencing symbols. In Java we don’t — why not? It’s because, apart from the primitive types, effectively everything is implicitly treated as a reference. In concrete terms, this means that when a variable is declared then Java only allocates space for the pointer or a reference allocated in the stack Only later when the variable is initialised is space allocated in the heap and the reference is updated to “point to” the heap block. What are the consequences follow from this Java language concept that the Java programmer must be careful of? In copying non-primitive types, you copy references and not entire objects. Consider the following examples: double x= 10; double y= x; The assignment to y copies the actual value of x but to y ’s memory location. For example this means that y ’s value is the same as x , but its location in memory is different, so that y++; results in y and x ’s values differing. Now try doing something similar, but using our Number class instead of a primitive type: Number Xx= new Number(10); Number Yy= Xx; We certainly have Xx and Yy ’s value being the same — but they are “even more equal than that”, because they are actually pointing to the same memory location. Consider now calling Yy.setVal(11) — are Xx and Yy still the same, even though it looks like we have only changed Yy ? Well, yes they must be, because the update changes the value in the heap location, and as we’ve already agreed, that’s the same, so changing Yy automatically changes Xx too. Method calls In Java, as in other languages, we can pass parameters in method calls. However in Java: All parameters are passed-by-value This means that when a function is called, any modifications take place on copies of the parameters. For example what does the following program output? public class Inc { public static void main (String args[] ) { int i= 0; addOne(i); System.out.println("i is now " + i); } public static void addOne (int i) {i++;} // parameter i is passed by value } As for the usual interpretation of pass-by-value the increment is performed on a copy of the parameter. (Exercise: how is it possible to write a method that does do an increment?) On the other hand a variable declared as an object type is actually (by value!) a reference, and so when these variables are passed, the internals of the object can be changed as normal. For example, suppose we were to write an Inc function inside of Number : public void Inc(Number i) {i.mMagnitude++;} and use it in the fragment: Number n= new Number(0); Number.Inc(n); System.out.println("n is now " + n; What is the output of the program? What happens if you forget to create an object? In some compilers (eg some C compilers) some primitive types are “automatically” initialised on creation. In Java, declaring an object of a particular class does not normally mean that it is initialised; accessing an uninitialised variable will result in an error. Experiment in Eclipse to see what sort of error it generates. For example Number Cc; Cc.toString(); Declares a reference to a Number , but its “contents” at this point are null; thus the subsequent call to toString will result in an error because there are no contents to print out. Type checking As you use Java you’ll find that errors of type mismatch will be reported. That’s because whenever a variable is declared as some particular type then the compiler will perform a consistency check to ensure that the programmer has not accidently introduced an error by trying to assign a value to a variable of the wrong type. Usefully this can be checked statically before the program is running — and it’s always good to have errors sorted out before the program is deployed! Luckily Java will automatically convert between some types for you, in particular between related numeric types, and between classes and their super classes. Here’s what is allowed: Implicit type conversion for primitive types. Java will automatically allow variables of these primitive types to be converted automatically; char ⇒ int int ⇒ long int ⇒ float float ⇒ double Implicit type conversion between hierarchies of classes. Java’s compiler allows automatic type conversion between a class and a superclass. SuperClass vImSuper= new SubClass(); In our Number class this means we can declare a Number , but assign it to a Complex number without problem (a complex number is a number): Number Dd= new Complex(2,3); But a Complex number can’t be assigned as a Number . Why not? Explicit Type Conversion Java allows the programmer explicitly to change the type of a variable (or case it), but care should be taken! For example between numeric types: float yy= 777777321; int zz= (int) yy; and double dd= 10.75e-4; zz= (int) dd; We may experience loss of precision however! We can also cast between related types: Number iMag= new Number(1); Complex jMag= (Complex) iMag; However think about what would happen if you tried to use the methods which apply to fully installed complex numbers, but not to ordinary numbers. Where would we see the error? Correctness of the cast is checked at runtime, so you must be sure you know what you are doing! Allocating and Deallocating memory We’ve talked at length about the need explicitly to allocate memory using the “new” construct. Luckily don’t need to deallocate explicitly using for example “delete” as you do in C++. That’s because the Java Virtual Machine does this automatically for you using a thing called the garbage collector. Briefly, the gargage collector looks at the heap and compares it with your program — if an object is not accessible from within your code then that object is deleted. As Eckel notes, Garbage Collection is only about memory cleanup, and so if there are some things that need to be done before the object is cleaned up then the programmer must do those tasks him or herself. Tasks of this nature are performed (among other things) by a special method public void finalize(); If defined in your class, it is run just before garbage collection. Consider a scenario where an object, as part of its creation, draws an image on the screen. If you do not ensure that the image is removed from the screen before the object is garbage collected then it will remain even after the object has been erased. You would put the code to erase the screen in finalize for that class. Basic inheritance The OO philosophy encourages inheritance between user-defined classes. This is a very important and useful structuring technique to introduce detail and specialise general ideas to specific cases. Defining an extension of a class means makes all the (protected and public) methods and data available to the extended class. In the Week 2 code bundle we see in the number package an extension of the Number class called Complex . The extension allows a class to be specialised by adding more detail or functionality. To state that a class extends (becomes a subclass of) another, we use the extends keyword in its definition. The extended class will still need a constructor, possibly extra fields and possibly to redefine the methods to be more appropriate for the extension. For example in the definition of Complex we see public class Complex extends Number{ protected float mAngle; // instance variable public Complex() { mAngle= 0; } public Complex(float _num, float _arg) { // constructor super(_num); mAngle= _arg; } ... Here we can see that we add an extra field to provide an angle — recall that all complex numbers can be specified with two pieces of data, a size, and an angle (in maths books you often see , where corresponds to mMagnitude and theta corresponds to mAngle ). In this case we say that Number is the “superclass” of Complex , and Complex if the “subclass” of Number . Note that the extension might not have access to the fields of the superclass. For example if the superclass fields are labelled private then they are not available. To make them available you must declare them as protected in the superclass definition. In general protected fields are accessible to all subclasses which are in the same package as the superclass but nothing else. (The default, ie if you leave off any protection at all is that it is accessible by everything in the same package (whether or not the classes are related by inheritance).) Overriding One of the things that you can do inside of a subclass is redefine the functions to be more appropriate for the subclass. For example in Number we have a method equals which determines whether the value of two numbers is the same or not by comparing their respective mArgument fields. Of course with the extra field mAngle in a fully installed Complex number we not only have to compare their mArgument but also their mAngle as well. So we override equals simply be redefining it. Take a look at the code 1 public boolean equals(Complex _cNum) { if (_cNum != null && _cNum instanceof Complex) { return (super.equals(_cNum) && this.mAngle == _cNum.mAngle); } else return false; } Here we have used the construct super to refer to the superclass Number ’s equals method making this as convenient way to reuse code that’s already been developed for the superclass. We have similarly defined other methods — take a particular look at toString — you’ll find that this is often included in a class as a way to give the application programmer access to the actual representation of the class. Generally the toString method provides a textual (ie String) interpretation of the internal representation in as concise and informative way as possible. As some other examples of inheritance I’ve also provided the people package, which I’ll briefly talk about in lectures. A brief reflection: Java and OO design By now you’ve been programming a fair bit in Java and, in the process, have learned a lot about Java’s syntax and structuring technology. But how does Java help us to organise our own programs so that the follow an OO design? Just because a program is written in Java doesn’t make it follow an OO design; however but because Java forces us to build our own classes and makes available the idea of inheritance, and the associated concepts of abstract classes and interfaces means that Java supports us in our endeavor to create OO designs. That means, of course, decomposing a problem and identifying components which can be programmed more easily and correctly. One way to appreciate good design is to have a (brief) look at a bad design and to try to figure out what makes it bad. Take a look at the SimpleNim archive available as a Week 3 download on Moodle. It contains a program to implement a very simple game of Nim. Nim is an ancient game which starts with several piles of matches; each player takes turns to remove matches, and the player who removes the last pebble loses. There are many variations of the game, usually restricting how many matches players can remove, or restricted them to removes from exactly one pile per move. The simple program assumes that there is a single pile of matches. It has a simple text input and output interface. Critique You’ll notice that there is a single class called Nim with two variables, one to store the number of matches left and the other to record which player can play. There are a number of methods for calculating things like whether the game has ended, how many matches are to be taken etc. Although it’s written in Java however, the design of the game does not conform very well to an OO design. Here are some reasons why, there are probably many more. This program does not smoothly handle errors; although it does prompt the user to “try again” if he tries to take too many matches, or types something which does not correspond to a number at all. However that error analysis is a task which does not have anything to do with the logic of the game. An OO solution is to handle errors via a customised exception class. Java supports this by allowing users to extend its Exception class, customising appropriately. The main game logic is mixed up with the tasks of player input and result output. This problem would be compounded in a program which used a GUI to organise user input and display the result of a move. (As you have seen already there are many lines of Swing code required even to implement a “Hello World” program. Imagine trying to isolate the game logic from that if it were all mixed up together, as this code is.) An OO solution is to identify the game logic, the functions and state which characterise it; further embellishments on this would identify what a move is, what happens when a move is made. Java supports this in allowing the user to create classes for each clearly identified program feature. The problem with this code is that it cannot easily be extended except by re-engineering the whole thing. In a standard computer game rendering of eg Nim would include an “Undo” and “Redo” facility, and a “Save game”. Without properly identifying the logical parts of the game, it is very difficult to add these and other features in. Error handling As we have seen, there can be many kinds of errors during program development; possibly the worst ones of all are errors which cannot be picked up at compile time, but are caused by unexpected conditions as the program runs. Java provides a way for the programmer to handle and deal with such errors. Exceptions: a first look An exception is an “unexpected” condition in a program. The fact that it’s unexpected means that normally the program would break in some unpredictable way; exception handling is available to the Java programmer as a way for him to specify how the program should recover in the case of these unexpected circumstances. Examples of exceptions You’ve probably come across exceptions yourself, for example when running web-based programs. Usually the program will abort and print an error message eg to the webbrowser. In the worst cases, if errors are not properly handled the whole machine might crash (recall some of the 9 worst errors from Lecture 1). In particular look at the following error messages and their meanings: Exception in thread "main" java.lang.Error: Unresolved compilation problem: The local variable r may not have been initialized at akm.myTest.main(myTest.java:9) This was caused by the uninitialised object: Number r; System.out.println(r.toString()); Here’s another example: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1 at akm.myTest.main(myTest.java:17 This was caused by out of bounds error: int [] myArray= new int[1]; myArray[0]= 0; myArray[1]= 1; Java’s exception handling: provides a uniform approach to error handling (rather than ad hoc approaches which can be platform specific); avoids mixing error code with normal code encouraging cleaner and easier-to-understand source code; systems requiring failsafe and high assurance, correct error handling is essential in the design of the system. Java’s exception handling mechanism Java gives the programmer control over error handling using the exception class. Whenever an unexpected condition is encountered we say that “an exception is raised” — the programmer deals with it by extending Java’s exception class to encapsulate information about the error inside of the exception object. This might include providing appropriate error messages or taking action to recover from the unexpected condition. Exception handler When an unexpected condition occurs Java provides the programmer the means to deal with it via exception objects. This is what happens If a problem arise then an exception can be thrown A thrown exception has an associated exception object which includes things like a description of the failure and what to do about it; A calling method can either throw the exception on for something else to sort out or catch it and sort it out itself; If the thrown exception is not caught and dealt with by something the program halts and reports an error message. A hierarchy of exceptions Exceptions are modelled in a hierarchy of exception classes. An example of some of the major exception classes in Java is depicted in the diagram below. The superclass of all errors and exceptions is the Throwable class; there are different kinds of Throwable ’s, but the main ones are Error Exception and RuntimeException . This is what they mean: Error These are generally unrecoverable; they are thrown by the JVM (Java Virtual Machine) and not usually handled by Java programs. Exception These can be adapted for any program by inheritance; below we’ll explain specifically how to do that. RunTimeException These are subclasses of Exception to cover many of the common errors that occur in programs, for example array out of bounds, null pointer etc. image/svg+xml Throwable Error Exception RuntimeException java.lang Errors and runtime exceptions are known as unchecked exceptions which means that the compiler does not ensure that they are handled by the application code; all others are called checked exceptions. For those the compiler makes sure that whenever a method might raise a checked exception then either: it provides some exception handling code for that exception or; it is flagged as emitting such exceptions, which must then be (ultimately) handled by code which calls that method. Java’s exception handling mechanism throw raises an exception of a given type, unwinds the call stack to the first occurrence of a compatible exception handler; throws is a method modifier describing the exceptions that may be thrown by that method; try marks the start of a block of code which is guarded by the exception handler; catch marks a block of code which will be executed if the corresponding exception is thrown from within the enclosing try statement; finally is a default handler which is always executed as execution leaves the scope of the enclosing try . Exceptions are handled within try — catch /finally blocks, with general set up as follows: try { // Code which might raise an exception } catch (ExceptionType1 eCaught) { // Handler for type 1 errors } catch (ExceptionType2 eCaught) { // Handler for type 1 errors } finally { // Optional - always executes when the try block is exited (after any catches) } catch blocks are actually searched sequentially for one that matches a raised exception. The impact of this is that the catch block for subtypes should come before those of its supertypes. Below is an example of a try — catch block in action. Here we use a special AKMException which has been declared as an extension of Java’s Exception class elsewhere. (See the next section and the code bundle for this week for how to do that.) Here we have a very simple exception handler which just prints out an error message to the console. We’ll look at other options for dealing with exceptions in the next section. try { .... // statements here AKMException bb= new AKMException; throw bb; } catch (AKMException bb){System.out.println("Just caught Annabelle's exception");} Methods can be defined so that they throw exceptions in unexpected conditions. To do that we’d see in the method definition public void methodName() throws AKMException { ... throw new AKMException(); ... } In the next section we’ll go through the main steps for handling errors via your own exception class in Java. Programming your own exceptions There are two main tasks you have to do when writing your own exceptions: Make your own exception by extending Java’s exception class; Perform error handling where one of the possibilities is now to throw one of your exceptions, in a throw clause, but then to deal with it is a catch clause. Installing your own exception class in the exception hierarchy Have a look in the program ExceptionHandling.java in this week’s program examples. Inside you’ll see a small class called AKMException which extends the class Exception . It includes data which is called errorCode which will turn out to be a useful way to deal with different kinds of errors and to assign each its own individual code; the only other thing in the class is a constructor. class AKMException extends Exception { private static final long serialVersionUID = -712061786161146677L; int errorCode; AKMException(int _errorCode) { errorCode= _errorCode; } } Using your own exception class to deal with input errors Have a look in the rest of that file to see how AKMException s are used to handle the different kinds of input when they are not the intended ones. This mockup allows users to input two integers with the first integer being no more than the second. (Think of a web-based interface for booking airline tickets with the departure date coming before the return date!) You’ll see that checking the input is valid involves a number of things, inluding: checking that the input is a single character, that it is a numeric input (rather than letters or punctuation), that it is in the correct range, etc. In this example these are all handled by throwing an exception with a specific id. For example interpretInputs examines the two inputs and throws various exceptions in the cases that the inputs do not comply with those intended: static boolean interpretInputs(int _d1, int _d2) throws AKMException { int n1= _d1-'0'; // coverting a character to an int int n2= _d2-'0'; if (n1<1) throw new AKMException (954); // _d1 out of range if (n2<1) throw new AKMException (955); // _d2 out of range if (n2 return (n1 <= n2); } A separate function deals with the error codes: static String errorDescription(int _errorCode) { String errorText; switch (_errorCode) { case 2000: errorText= "End of file"; break; case 2001: errorText= _errorCode + " (No input recorded)"; break;// Replace these similarly with the text you really want. case 2002: errorText= _errorCode + " (You did not type a character 1--9)"; break; case 954: errorText= _errorCode + " (Day 1 is out of range)"; break; case 955: errorText= _errorCode + " (Day 2 is out of range)"; break; case 956: errorText= _errorCode + " (Day 2 should not come before Day 1)";break; case 1103: errorText= "" + _errorCode + " (IO error)";break; case 1135: errorText= "" + _errorCode + " (You did not input a single character)"; break; default: errorText= "" + _errorCode;break; } return "Error: " + errorText + "\"."; } The errors are handled within the main program inside the try \dots catch clause. Note that going the error handling via exceptions provides a uniform way to deal with exceptions, and removes the error code from the main logic of the program (which is just to input two valid numbers, and then presumably do something else afterwards.) In the next development of the Single Pile Nim game, we’ll use this idea to deal with errors encountered with user input. More on inheritance Class Definitions Java provides the following modifiers to classes: public Accessed by any class; {default} Accessed by classes in the same package; abstract Cannot be instantiated; may have abstract methods which do not have implementations; final Can’t be subclassed. We’ll say more about abstract classes below when we discuss class hierarchy in more detail. Mixed class exercises TextBox Write a simple application which allows the user to enter three numbers into text fields and then, in response to a button press, multiplies those numbers together and displays their product in a fourth (non-editable) field. Have a look at the DisplayNumber class to help get you started. Note: this task requires you to convert the text in a field into a double precision number, which you can do using the static parseDouble() method of the java.lang.Double class . To convert back from doubles to strings you can use the static valueOf() method of the java.lang.String class. GUI Load the lecture bundle into your Eclipse workspace using the import facility examined in last week’s practical. Now spend about 10 minutes familiarising yourself with how some of these GUI applications work. In each case, identify the lines of code which have to do with creating and laying out the various components in the GUI relative to each other. Make sure you understand how the “physical” layout of the GUI you see on the screen relates to the source code that creates it. Also make sure that you are comfortable with the way that the code specifies how changes to the application’s state are made in response to user actions like button presses. Debug Is the following code legal? try { System.out.println("Do finally blocks need..."); } finally { System.out.println("...associated catch blocks"); } System.out.println("The next statement goes here!"); If it is, what output would this code produce were it to be executed? Exception Suppose that DomsException is a sub-class of Exception and consider the following code: try { throw (new DomsException()); } catch (Exception e) { System.out.println("Caught an exception!"); } catch (DomsException e) { System.out.println("Caught Dom's exception!"); } finally { System.out.println("This is the finally block!"); } Will this code compile? If it does what output will it produce? Do you think this exception handler works in the way the programmer intended? If not, say what you think he really meant the outcome to be, and then rewrite the block to correct it. Tests Write some JUnit tests for your FullTime and PartTime . Adapt For this question, have a look at the code in images package and work out what it does. Now adapt it to a simple application which shows two images and a single button. These images can be any PNG (portable network graphics) images you like - try searching on the internet for some interesting images. Set things up so that each time the button is pressed it cycles through a sequence of changes in which first both of the images is shown, then only the first image is shown, then only the second image is shown and finally both images disappear. Pressing the button one more time should cycle your application back to the beginning with both images shown. As it stands, this code will not always deliver the correct result, since it deems two Complex numbers to be the same provided their mAngle fields and mArgument fields are the same. Strictly speaking we should take into account multiples of .↩ by Matt Roberts based heavily on notes by Annabelle McIver and Dominic Verity