CIS 121 April 26, 2000


Review for the Final Exam - Part I


  • What is the syntax of the header of a class definition?

  • What are formal parameters?

  • What are actual parameters?

  • What are instance variables?

  • What are instance methods?

  • What are class variables?

  • What are class methods?

  • How do we distinguish between instance variables/methods and class variables/methods

  • What is a constructor?

  • What is the purpose of a constructor?

  • What are the four choices for access control keyword?

  • What is a default package?

  • When do we use the keyword this?

  • What is the method toString used for?

  • What is a default constructor?

  • When is a default constructor used?

  • What is method overloading?

  • How many constructors can a class have?

  • What is a local variable?

  • What is an ADT?

  • What is encapsulation?

  • What is information hiding?

  • Explain where variables and methods are available when using the four access control keywords

  • What are the three aspects of good code design and explain each? (cohesion, competent/complete classes, and loose coupling)?

  • What are the rules for creating named packages?

  • What are the rules for using the default package?

  • How does the compiler and interpreter use the environment variable CLASSPATH?

  • What is the finalize method?

  • What is garbage?

  • What is garbage collection?

  • How does garbage collection happen?

  • What are the seven major components in a class definition?

  • What does the StreamTokenizer do?

  • Explain how StreamTokenizer works

  • In what Java package is StreamTokenizer located?

  • What is a deprecated feature?

  • What is the Java keyword used to create an object?

  • How does it work?

  • What is a static initializer?

  • What does a static initializer do?

  • What is the syntax of a static initializer?

  • What is an inner class?

  • When do we use a class variable?

  • When do we use an intance variable?

  • When do we use a local variable?

  • What is inheritance?

  • What type of inheritance does Java support?

  • What keyword is used to implement inheritance?

  • What is the class hierarchy?

  • What is the top level of the class hierarchy?

  • How does Java deal with constructors when we use inheritance?

  • What does the super statement do in a subclass constructor?

  • What is the rule for using the super statement in a subclass constructor?

  • What happens if there is no super statement in a subclass constructor?

  • How do we override methods?

  • What are interfaces?

  • What is the Object class?

  • How can we use the Object class in our methods?

  • What are concrete methods?

  • What are concrete classes?

  • What are abstract methods?

  • What are abstract classes?

  • How do we use features from the parent class in a subclass?

  • What is polymorphism?

  • What is an example of polymorphism?

  • What does the boolean method equals do?

  • How do we use the equals method?

  • What are the four ways to obtain packages to solve real problems in Java and what is the order of preference?

  • When using the extends clause to implement inheritance, what are the four ways of describing the relationship between the classes involved?

  • What does implementing interfaces allow us to do with unrelated classes?

  • What are two examples of interfaces?

  • What is a clone?


    Review for the Final Exam - Part II


    In order for a Java application to run, it must have a main method.

    An exception is a event which occurs that makes program execution either impossible or undesirable.

    Java implements a termination model for exception handling. This means that when an exception is thrown (and is not dealt with in a catch block), the interpreter will terminate execution instead of resuming.

    The Throwable class is the ancestor of all exceptions. It has two main subclasses, Error and Exception. The classes that inherit from Error are error which cannot be handled by the user. Such events are running out of memory during execution of a program. These errors cannot be recovered from. The classes that inherit from Exception are those that can usually be recovered, with at least one exception. The RunTimeException class represents errors which cannot be recovered from The IOException class is a descendant of the Exception class and acts as a parent class for various I/O Exceptions.

    We may also define our own exceptions.

    Java provides a construct for us to use to handle exceptions. This is the try-catch block. The try portion acts as a wrapper for code which might possibly cause an exception to occur. In the catch block(s) we define code to deal with exceptions which may occur when the code in the try block is executed. If an exception is thrown and there is no catch block to deal with it, then Java deals with the exception(s) as it would if there were no try-catch block. An optional block called finally may be added to a try-catch block. The code within finally, if it is defined, is executed whenever the try-catch block is exited even if no exception was thrown in the try block. This allow us to release any system resources we might have used in the try block. This block is similar to the finalize method which can be placed in class definitions.

    There are two other keywords that are related to exceptions. One is throw and the other is throws. throws is placed in the header of a method and is followed by the name of an exception to indicate that the code within the method might possibly generate that exception. throw is most commonly placed in the body of a try block and is followed by a call to the constructor of an exception class. It creates a new instance of the exception and throws to the catch blocks if there is one defined to handle the exception.

    Recall that methods can be classified as either abstract or concrete. A concrete method is a method which has an implementation. An abstract class has no implementation.

    Classes can also be classified as either abstract or concrete. A concrete class is a class in which all its methods are concrete. An abstract class is one is which at least one of its methods is abstract.

    If a class is abstract we cannot create objects from it. We can use the keyword abstract in the header of a class to indicate this.

    An interface is a Java construct that only contains abstract methods or interface constants.

    Examples of interfaces are Cloneable and Serializable.

    Cloneable is an interface which contains the method clone(). This allows us to create an identical object with its own space on the heap.

    Serializable is an interface which allows us to write out objects to a file.

    In order to use an interface we place the keyword implements followed by the name of the interface in the class header. As the name implies we must implement the interface. That is, we must implement each method defined in the interface within our class.
    There is a very important and powerful aspect of implementing interfaces. Since an interface is an object it can be used as a parameter type. Any oject that is instantiated from a class that implements an interface is a valid parameter to a method with that interface as a parameter type. For example,

    In the method public void createClone(Cloneable c), if we create an object from a class that implements the Cloneable Interface, then we may send that object to createClone.

    When we implement an interface we must implement all the methods in the interface. If only one of the methods is important to us, then we must also implement all of the other methods, but we can simply give the ones that aren't important to us null bodies.

    Polymorphism allows a given method call to be implemented in different versions.

    Graphical User Interfaces

    Java provides support for Graphical User Interfaces with the AWT package. AWT is an acronym that means Abstract Windowing Toolkit. It contains all the classes necessary to create and use Graphical User Interfaces.

    One of the main classes found in the AWT package is the class Component. Component contains many important methods. Among those are the following.

    public void setSize(int width,int height) - used to set the width and height in pixels of the Component
    public void setBackground(Color c) - used to set the background color of the Component
    public void setVisible(boolean b) - used to make the Component visible or invisible
    public void setLocation(int x,int y) - used to set the Location of the upper left-hand corner of the Component
    public Graphics getGraphics() - used to create a Graphics object associated with that Component
    public void paint(Graphics g) - used to draw Graphics on a Panel or Applet
    public void update(Graphics g) - used to clear the drawing area before making a call to paint
    public void repaint() - used to make a call to update as soon as the controlling environment (browser/appletviewer) can

    One of the subclasses of Component is Container. Within Container there are some important methods that we use when creating Graphical User Interfaces.

    public Component add(Component comp) - used to add a Component to a Container
    public void setLayout(LayoutManager mgr) - used to set the Layout of the Container

    There are several predefined Layout Managers including FlowLayout, GridLayout. A FlowLayout manager places components in rows until a row is filled, then components are placed on the next row. GridLayout allows us to place components within a container in a grid. We may also choose to use no Layout manager. In this case, we use null as a parameter to setLayout.

    An important subclass of Container is Window. Within the Window class, there is one important, addWindowListener, the signature of this method is

    public void addWindowListener(WindowListener l)

    An important subclass of Window is Frame. A Frame has a boundary around it and a Title Bar. An important method within the Frame class is public synchronized void setMenuBar(MenuBar mb)

    The Menu and MenuItems are specific to Frames. We cannot place them in containers like Panels.

    An important aspect of Java and Graphical User Interfaces is that we can implement event-driven programming. This is characterized by times when your program is "doing nothing" and when the operating system is "listening" for user input.

    There are several Components we can place into a Container which can implement event-driven programming.

    There are several interfaces which were written to implement event-driven programming.
    Interface Methods
    ActionListener public abstract void actionPerformed(ActionEvent e)
    ItemListener public abstract void itemStateChanged(ItemEvent e)
    MouseListener public abstract void mouseClicked(MouseEvent e)
    public abstract void mousePressed(MouseEvent e)
    public abstract void mouseReleased(MouseEvent e)
    public abstract void mouseEntered(MouseEvent e)
    public abstract void mouseExited(MouseEvent e)
    WindowListener public abstract void windowActivated(WindowEvent e)
    public abstract void windowClosed(WindowEvent e)
    public abstract void windowClosing(WindowEvent e)
    public abstract void windowDeactivated(WindowEvent e)
    public abstract void windowDeiconified(WindowEvent e)
    public abstract void windowIconified(WindowEvent e)
    public abstract void windowOpened(WindowEvent e)
    TextListener public abstract void textValueChanged(TextEvent e)

    There are several Components that can be placed in a Container and cause events to occur. We have discussed in detail the following.
    Component Event Generated
    Button ActionEvent
    Checkbox ItemEvent

    There are other Components that can be placed in a Container but these are the two that we have discussed. Recall that we can also create Radio Buttons by using a Checkboxgroup as a parameter to a constructor of the Checkbox class. When Radio Buttons are created only one of them can be selected at a time.

    In order for the interpreter to listen for these events to occur there are methods which we must call.

    Component Code added
    Button addActionListener(ActionListener l)
    Checkbox addItemListener(ItemListener l)

    When we run an application it runs in its own window. We can use the method addWindowListener to cause the interpreter to listen for Window Events such as closing the Window.

    Recall again the importance of Interfaces as parameter types. The object we pass to addActionListener must be an object that is created from a class that implements the ActionListener interface. A common parameter used in a call to addActionListener is this. this is only appropriate if the class we are defining implements the interface ActionListener. There are instances in which this would not be a valid parameter to methods like addActionListener. We will see an example of this when we look at Threads.

    In order to deal with events that occur from these Components we need to implement the interface associated with the listener we place on that Component. The two main interface method we have implemented are public void actionPerformed(ActionEvent e) from ActionListener and public void itemStateChanged(ItemEvent e) from ItemListener.

    When we handle events there are several methods that are important. When we handle an event occuring from an ActionEvent, we have getActionCommand() and getSource() available. getActionCommand() returns the text associated with the Component that caused the event to occur. getSource() returns an object. When we handle an event occcuring from an ItemEvent, we have getItem() which for our purposes returns the label of the Checkbox which was checked or unchecked.

    Recall the sequence of events when we detect and act on button clicks and detect and act on checking or unchecking a checkbox.
    Button clicks
    1. We create the Button object button with buttonLabel and add it to a Container.
    2. We tell the interpreter to listen for button clicks by adding the line button.addActionListener(this);.
    3. When the user clicks on the Button an ActionEvent object is created and the method actionPerformed is called.
    4. Within actionPerformed we can either use getSource() or getActionCommand() to determine the button click that caused the event to occur.
    Checking or unchecking a checkbox
    1. We create the Checkbox object checkbox with checkboxLabel and add it to a Container.
    2. We tell the interpreter to listen for checking or unchecking by adding the line checkbox.addItemListener(this);.
    3. When the user checks or unchecks checkbox an ItemEvent object is created and the method itemStateChanged is called.
    4. Within itemStateChanged, we use the method getStateChange() to determine whether the box was checked or unchecked. We can use the two static integer variables ItemEvent.SELECTED and ItemEvent.DESELECTED to detect whether or the event that triggered the call to itemStateChanged() was a checkbox being checked or unchecked.
    5. After we have determined whether or not the event was a checkbox being checked or unchecked we can use getItem() to get the label of the checkbox that was checked or unchecked.
    We have also used TextFields. We have used two important methods with TextFields, getText() and setText(). Recall that the object in a TextField is a String. If we wish to use this as an integer, double, float, etc., then we must convert the String. We can do this by using the static class method valueOf which is located in the appropriate class. For example, if we wish to convert the String to an int, then we make a call to the static class method valueOf in the Integer class. This will create an Integer object, and then we can use the intValue() method to place the value into an int variable. For example, if we have a TextField component named textField, then to convert the String in that TextField to an int called myInt, then we would use the following code.

    myInt = (Integer.valueOf(textField.getText())).intValue();

    Recall that the classes ActionEvent, ItemEvent, etc., and the interfaces ActionListener, ItemListener, etc. are found in the java.awt.event package.

    Another important class we have discussed is the Applet class. This class is found in the java.applet package. The Applet class is a subclass of Panel which is a subclass of Container.

    An applet, unlike an application, cannot run by itself. It must be run in the context of a web browser or appletviewer. In order to run an applet we must create an HTML file containing a tag which will load the applet. HTML is an acronym that means Hypertext Markup Language. It is the language in which web pages are written. HTML contains tags which a web browser can interpret. The following is the HTML code which is needed to load and execute an applet.

    <applet code=MyApplet width=w height=h>
    </applet>

    width and height are measured in pixels and tell the browser how large the applet is. MyApplet is the name of the class file created from compiling the source code for the applet.

    We can send values into an applet from HTML. We do this by using the tag

    <param name="myname" value="myvalue">

    Within the applet we would call the method getParameter("myname") to retrieve the value myvalue.

    There are seven methods which are commonly implemented in Applets even though can implement other methods such as those from Interfaces. These seven methods are
    1. public void paint(Graphics g) - normally used to draw graphics on a Panel or Applet
    2. public void update(Graphics g) - by default will clear the entire drawing area and then call paint
    3. public void repaint() - makes a call to update as soon as the controlling environment (browser/appletviewer) can
    4. public void init() - is executed one time when an applet is loaded
    5. public void start() - is executed each time an applet becomes visible
    6. public void stop() - is executed each time the applet becomes invisible
    7. public void destroy() - is executed one time when the controlling environment (browser/appletviewer) is closed
    The first three methods are inherited from the Component class. The last four are inherited from the Applet class.

    The Graphics class is an abstract class, and, therefore, a Graphics object cannot be instantiated through a constructor. It must be created through a call to getGraphics(). There are several methods that may be used by Graphics objects.
    public abstract void clearRect(int x,int y,int width,int height)
    clears a rectangular area whose upper left-hand coordinate is (x,y) with the specified width and height

    public abstract void drawLine(int xl,int yl,int x2,int y2)
    draws a line from (x1,y1) to (x2,y2)

    public abstract void drawOval(int x,int y,int width,int length)
    draws an oval whose bounding box is a rectangle whose upper left-hand corner is (x,y) with the specified width and height

    public void drawRect(int x,int y,int width,int height)
    draws a rectangle whose upper left-hand coordinate is (x,y) with specified width and height

    public abstract void drawString(String str,int x,int y)
    draws a string on the Panel or Applet at the coordinates (x,y)

    public abstract void fillOval(int x,int y,int width,int height)
    draws an oval like drawOval does but fills it with the drawing color

    public abstract void fillRect(int x,int y,int width,int height)
    draws a rectangle like drawRect does but fills it with the drawing color

    public void drawPolygon(int xpoints[],int ypoints[],int points)
    draws a polygon on the Panel or Applet whose coordinates are specified in the arrays xpoints and ypoints and the number of points in the polygon specified by points

    public void fillPolygon(int xpoints[],int ypoints[],int points)
    draws a polygon like drawPolygon does but fills it with the drawing color

    public abstract void setColor(Color c)
    sets the color to use for drawing


    Note that the call to drawOval and drawRect are almost the same. The difference is that in the drawOval method, an oval is drawn so that it will touch all four edges of the rectangle specified. This rectangle is called the bounding box. If we use different values for width and length, then the oval will be an ellipse. If we use the same value for the width and lenght, then the oval will be a circle.

    Recall that when an applet is loaded the first method that is executed is the constructor if there is one. The next method run is the init method. Then the method start is run since the applet becomes visible. If we place code such as an infinite loop in the start method, then no activity will occur even if we make a call to repaint. This is because the call to repaint calls update to call paint as soon as it can. That is, as soon as the controlling environment (browser/appletviewer) regains control to be able to call update. This is because the browser/appletviewer is running in what is called a thread.

    A thread is a single sequential flow of execution. The browser/appletviewer is running in its own thread and can only make a call to the paint method one it has control of the thread. If the code in the start method contains an infinite loop or code that takes a very long time to execute, then the browser/appletviewer may not be able to regain control of the thread.

    To solve this problem we must run the Applet in its own thread so that the two threads can execute simultaneously. Since the CPU can only do one thing at a time, the OS will simulate simultaneous execution by quickly swapping the two threads in and out of the CPU.

    There is a class called Thread in the java.lang package. Since applets must extend the Applet class, and Java does not support multiple inheritance we cause an applet to run in its own thread by implementing an interface called Runnable. The Thread class itself implements the Runnable interface. The Runnable interface contains one method, public void run().

    There are several class methods in the Thread class which we can use.

  • public void start() - starts a Thread running and calls the run() method

  • public void suspend() - suspends the execution of the Thread

  • public void resume() - resumes execution of the Thread

  • public void stop() - stops the Thread permanently

  • public void sleep(int milliseconds) - pauses execution of the Thread for the specified number of milliseconds. This method must be placed inside a try block and you must have a catch block to handle an InterruptedException. This can occur if the user exits the browser/appletviewer while the thread is sleeping

    Recall that these methods are not run on their own. The first four are instance methods in the Thread class, and sleep is a class method in the Thread class.

    In order to create a new instance of a thread we make a call to the constructor of the Thread class. This constructor has a parameter which is of type Runnable. Since Runnable is an interface any object which is instantiated from a class which implements Runnable is a valid object of type Runnable. We have seen class in which the call to the Thread constructor resembled the following.

    thread = new Thread(this);

    This is only valid if the current class implements the Runnable interface. As we have seen we can place inner classes in our applet which are themselves Runnable and can instantiate Threads using object of these inner classes as a parameter. The Applet does not need to implement the Runnable interface. If it does not, then sending this as a parameter to the constructor of the Thread class is not valid. For example, suppose we have an inner class called Timer which implements the Runnable interface. To create a new thread in which to run an instance of Timer we could use the following code.

    thread = new Thread(new Timer());

    Normally the init method is used to start a thread. The initial value of a thread is null until it is assigned a new instance of Thread. Normally the destroy method is used to stop a thread and then nullify it to free system resources.

    Review for the Final Exam - Part III


  • Stack - A stack is a LIFO data structure, that is last element in is the first element out.

  • There are several intrinsic operations related to a stack: push (add an element to the stack), pop (remove an element from the stack), peek (examine the element on top of the stack without removing it), isEmpty (determine whether or not the stack is empty), and search (find the position of an element in the stack).

    push - place an element on to the stack.

    pop - take an element off the top of the stack.

    peek - examine the element on the top of the stack without taking it.

    empty - determine whether or not the stack is empty.

    search - search for the position of a particular element of the stack.

    The interface for the Stack class is the following.
    public class Stack extends Vector {
       public Stack();
    
       public boolean empty();
       public Object peek();
       public Object pop();
       public Object push(Object item);
       public int search(Object o);
    }
    
    This class is found in the java.util package.

  • These operations are implemented for us in the JDK using Vectors.

  • A Vector unlike an array can grow dynamically. An array's size must be declared up front.

  • The constructors for the Vector class are:
    Vector() - creates an empty vector with initial capacity 10.
    
    Vector(int cap) - creates an empty vector with initial capacity cap.
    
    Vector(int cap,int grow) - creates an empty vector with initial capacity
                               cap and growth factor grow.
    
    Some methods available to us in the Vector class are:
  • Unlike an array, a vector can only hold object references, so we must keep track of what we place in the vector so that when we remove it we can cast it back to the appropriate object type.

  • Queue - A queue is a FIFO data structure, that is first element in is the first element out.

  • There are many natural examples of a queue such as a queue of print jobs or a queue of threads.

  • There are a few intrinsic operations related to a queue: enque (add to the queue), deque (remove an element from the queue), and isEmpty (determine whether or not the queue is empty).

  • A queue can be implemented in different ways one of them being a linked list.

  • A list is an abstract data type which we can implement in Java.

  • In languages such as C++ there are variable types called pointers which contain the address of an area of memory.

  • Java does not contain a pointer variable. However, Java does have support for self-referential structures. These are class definitions which contain a variable whose type is the class. An example of this is the following.
    class Node {
       private Object datum;
       private Node link;
    
       public Node(Object item,Node pointer) {
          datum = item;
          link = pointer;
       }
    }
    
  • There are several differences between arrays and linked lists. One of them is that the size of an array must be declared when it is created whereas a linked list can grow dynamically as long as there is available memory. Vectors gives us flexibility but not efficiency. Not all languages support vectors.

  • We discussed several methods related to linked list such as insert, delete and traverse. Here are some example implementations.
    public void insert(Object datum) {
       if (head == null) {
          head = new Node(datum,head);
          tail = head;
       } else {
          temporary = new Node(datum,temporary);
          tail.link = temporary;
          tail = temporary;
          temporary = null;
       }
    }
    
    Notice here that this implementation of the insert method is for a queue. The important thing to keep in mind when inserting a node into a linked list is that when we locate the position to place the new node we
    1. Set the new node's pointer field to the node which will follow it in the list.
    2. Redirect the node which was pointing at that node to point to the new node.
    public boolean delete(Object scrap) {
       Node previous = head;
    
       for (Node current = head;current != null;current = current.link) {
          if (current.datum.equals(scrap) && previous == current) {
             head = current.link;
             if (head == null)
                tail = null;
             nodeCount--;
             return true;
          } else if (current.datum.equals(scrap) && current.link != null)) {
             previous.link = current.link;
             nodeCount--;
             return true;
          } else if (current.datum.equals(scrap) && (current.link == null)) {
             tail = previous;
             previous.link = null;
             nodeCount--;
             return(true);
          }
          previous = current;
          return false;
    }
    
       public void traverse() {
          for (Node start = head;start != null;start = start.link)
             System.out.println(start.datum);
       }
    
  • We discussed the difference between singly linked lists and doubly linked lists. A singly linked list contains only one reference to an object of its type. A doubly linked list contains two references to an object of its type. A doubly linked list provides more flexibility since it allows us to have a "pointer" to the previous node and the next node.

  • We have also discussed the very powerful feature of a programmming language known as recursion. There are three criteria for a well-formed recursive method.
    1. It calls itself (directly or indirectly).
    2. It has exit criteria by which it does something without making the recursive call.
    3. It works with a "smaller" problem or value each time that it is called so that it can make progress towards the exit criteria!
    We discussed several examples of recursive methods. You will need to know these methods for the final.
       public int factorial(int num) {
          if (num == 1)
             return(1);
          else 
             return(num*factorial(num-1));
       }
    
       public int fibonacci(int num) {
          if ((num==0) || (num==1))
             return(1);
          else
             return(fibonacci(num-1) + fibonacci(num-2));
       }
    
       public int power(int exp) {
          if (exp==1)
             return(number);
          else
             return(number*power(exp-1));
       }
    
       public void writeBackwards(String s,int index) {
          if (index>=0) {
             System.out.println(s.charAt(index));
             writeBackwards(s,index-1);
          }
       }
    
  • We also discussed the Big O notation which measures the complexity of algorithms. That is, in the long run how long will the algorithm take to complete based on the number of elements in the construct we are dealing with. You will need to know the following chart for the final.

    Big O Class Another Name Shape of Graph Example Growth with double input size
    O(1) Constant Complexity Horizontal Line Add first two elements in an array None! No growth
    O(log N) Logarithmic Complexity Gentle curve up from left to right Binary Search Up by 1 - very slow growth!
    O(N) Linear Complexity Non-horizontal line Linear Search Doubles
    O(N log N) None Like a very flat parabola Quick Sort A little more than doubles
    O(N2) Quadratic Complexity Parabola Bubble Sort Quadruples

    Good Luck!