| Practice Final Exam Answers | |||||||||||||||
| PART
A: For each of the following three questions, indicate precisely what will be printed (or drawn) when the program is executed. HINT: Each of these programs does compile! For possible partial credit, show all of your work in the limited space provided. |
|||||||||||||||
| [1] |
class P1
{
public static void main (String args [])
{
int arr[] [] = { {24, 0, 19}, {21, 6, -5},
{10, 16, 3}, {1, -1, 0} };
for(int j = 0; j < arr[0].length; j++)
for(int k = 0; k < arr.length - 1; k++)
System.out.println( arr[k][j] );
}
}
|
||||||||||||||
You are used to setting up your nested for loops to have the outer loop control the row, and the inner loop the column. In this case, however, the two have been reversed; the outer loop controls the columns (note its boundary condition is arr[0].length), and the inner one the rows. Additionally, the inner loop (controlling the rows) is bounded by length - 1, so the last row elements will not print. In the print statement, they are also reversed, but the inner loop of rows increments before the column loop, thus printing out the first three elements in column 1 first, then column 2, etc. Note also that we are using println, not simply print, so each number is on its own line. |
|||||||||||||||
| [2] |
import javax.swing.*; |
||||||||||||||
|
|||||||||||||||
| [3] |
class P3
{
public static void main (String [] args)
{
A b = new B();
b.whoAmI();
}
}
class A
{
public void whoAmI()
{
System.out.println("I'm an A object!");
}
}
class B extends A
{
public void whoAmI()
{
System.out.println("I'm a B object!");
}
}
|
||||||||||||||
| This
program outputs the text: "I'm a B object!" Although the reference in main is declared with type A, the actual object that's created is of type B ( a subclass of A). Therefore, since the two method signatures are identical (think overridden methods - and see [4c] below), the method which is more specific for the object's actual type (based on the constructor that was used) is the one that is used. |
|||||||||||||||
| PART
B: Answer each of the following by writing between 2 and 5 clear, unambiguous English language sentences. |
|||||||||||||||
| [4a] |
The following code does not compile. Why not? Explain how to fix it!
ArrayList<int> numbers = new ArrayList<int>();
numbers.add(7);
numbers.add(19);
System.out.println( numbers );
|
||||||||||||||
| This code does not compile, because you cannot make an ArrayList (which holds kinds of Objects) with a primitive type - int - as its declared type. To fix it, replace the <int> with the Object equivalent <Integer>, and the code will then work. | |||||||||||||||
| [4b] | Explain two uses of the Java keyword this. | ||||||||||||||
| 1)
In a constructor, using this() with parentheses (and with or without
arguments) will call another constructor in the same class which has a
matching argument list. 2) When this is used without parentheses, either in a constructor or in another method, it refers to the object calling the method; it is most commonly seen when arguments being passed to the method have the same names as instance variables which belong to the class, or are objects of the same class. Using this.variableName will access the instance variable or instance method. 3) A third use, which you have learned with Swing, is that it can be used to pass the current object as a parameter to another object; an example is when your class acts as its own listener (by implementing the listener's interface) and then (this) is passed as the argument to addXXXListener() methods. |
|||||||||||||||
| [4c] | What is an overloaded function/method name? How is it different from an overridden function/method name? | ||||||||||||||
| An overloaded
method is one which has the same method name as another method in the
same class, but differs in its argument list (either in sequence or type
or both) from the other method. In this case, the method to be used is
determined by the argument list. An overridden method is one which has the same name AND arguments (exactly) as a method in its superclass; the subclass version will be used by objects of its type unless the superclass version is explicitly called using super. |
|||||||||||||||
| [4d] | In Java, all objects descent ultimately from the base class Object. State an advantage that Java derives from having all object types inherit from this class. | ||||||||||||||
| Having all classes ultimately derive from Object allows for standardization of objects, sets up the overall structure and hierarchy for inheritance and polymorphism, and sees that all objects have certain identical characteristics: 1) being accessed through a reference and stored in another area of memory; 2) having a few fundamental methods (in Object) which are thus defined and inherited by all classes (you haven't seen many of these yet - toString() is probably the most familiar one; equals() is another); 3) being able to test for membership in a class (instanceof); and 4) consistent support for Thread control, to name a few. | |||||||||||||||
| [4e] | A polymorphic variable is one for which the static type (the type associated with the declaration) may differ from the dynamic type (the type associated with the value currently being held by the variable at run time). How is this handled in Java? In other words, how can a programmer create polymorphic variables in this language? | ||||||||||||||
| Because
all objects ultimately derive from java.lang.Object, AND because any class
may only have one superclass, we can set up inheritance relationships
and know that a subclass object will meet all the criteria of its superclass
type. Therefore, we can create the reference (the static type)
to be of the superclass type (even an abstract superclass or an interface),
and make the object itself from the subclass type (the dynamic
type) by calling one of the subclass's constructors. This can be predetermined within the program code, or it can be left for the user's decision at runtime; as long as the constructor called belongs to a subclass of the static type, the object will work without problems, and in fact will use its own more specific methods if they override the superclass's methods. This ability to select the appropriate method "on the fly" at runtime is known as dynamic method binding or late binding. |
|||||||||||||||
| [4f] | The principles of data abstraction are very important in writing complex software that is easy to maintain. How does the public/private distinction for instance variables and methods in Java class definitions help one to create abstract data types (ADTs)? | ||||||||||||||
| By making
class data members private, and methods public, the implementation details
of the class can be kept hidden; the user never sees how the actual data
is stored or manipulated. Instead, the user is presented with a public
face (sometimes referred to as a public interface - not necessarily the
same as a Java interface, although it may be) that identifies the
methods available to the user (public methods) as an abstract data type.
Data cannot be manipulated except through these methods, thereby making error-proofing possible; it allows the methods' code (or data storage) to be modified or upgraded without the user's interaction being affected in any way; and objects of the class are much more reusable in a variety of programs or settings. |
|||||||||||||||
| In answering question [5] assume the Bitset class has been defined as discussed in lecture and in a course handout. You may assume the byteArray instance variable is public (not private) in answering this question. | |||||||||||||||
| [5] | Suppose
a Bitset named setA has been declared and properly initialized
to some value. What would be the effect of the statement setA.byteArray[0]
^= 17; Express your answer in terms of setA's resulting "set value." For example, your answer might state something like, "The value 17 is removed from setA if that value was already present. Otherwise this statement has no effect." |
||||||||||||||
| Recall
that the '^' symbol indicates the operator XOR, or Exclusive OR. This
operator will be true when ONE OR THE OTHER of its two operands is true,
but false when both are identical (trues OR falses). The operation we
are therefore performing is: 0000 0000 // or whatever byteArray[0] contains ^ 0001 0001 // 17 in binary ----------- 0001 0001 IF, however, either of those bits had been set in byteArray[0], XOR'ing them would have turned them off (thus removing the them from the set) instead of added them; so your answer should be that the bits or values represented by 17 (in Bitset, bits 0 and 4) will be set if they are not there, but removed if they are already present. |
|||||||||||||||
| PART C: Programming Problems | |||||||||||||||
| [6] | MIPS
Assembly Language Programming Write a MIPS subroutine named decode. This subroutine expects as its only argument a pointer to an ASCIIZ string that contains a "secret message" in lower-case alphabetic letters along with "punctuation." This "secret code" has every letter in the original message being stored as a character that is three ahead. In other words, the letter 'a' is stored as a 'd', the letter 'b' is stored as an 'e', ..., and the letters 'x', 'y' and 'z' have been converted into 'a', 'b', and 'c' respectively. Your subroutine should convert the secret message back into ordinary English. Thus, for example, if the encoded message is: mdyda!!! then your decode subroutine will return with this message now reading javax!!! Note that the encoded string (and the decoded result) might contain non-alphabetic characters. Upper-case alphabetic characters can be treated as through they are "punctuation." This subroutine is written using the standard MIPS conventions for argument passing and installing a stack frame, and so on. Most of the code is shown below. Fill in the missing pieces!
# E50b Final Exam, Spring 2001
# Decodes a message
.text
main: # SPIM starts by jumping to main.
# First read in string from the keyboard
la $a0, string_space
li $a1, 1024
li $v0, 8 # load "read_string" code into $v0
syscall
la $a0, string_space
jal decode
la $a0, string_space
li $v0, 4
syscall
li $v0, 10
syscall
decode: # Here is the subroutine!
subu $sp, $SP, 8
sw $ra, 4($SP)
SW $fp,
|
||||||||||||||
(A).
When we get to this point in the program, we've just tested for characters
less than 'a' and greater than 'z', so we know we have a valid character.
We now need to change its ASCII code by three less, so that it contains
the real letter, and if we end up less than 'a', correct by adding 26
to get the 'x', 'y', or 'z'.
subu $t3, $t3, 3 # subtract the 3 places
bge $t3, 'a', incr # if the letter is still greater than or
# equal to 'a', go to incr; we don't need
# to correct for the last three letters.
addu $t3, $t3, 26 # The letter was less than 'a', so we need
# to correct it, then go on to incr.
(B).
Here, we've finished dealing with the individual letter, and we need to
leave the subroutine by returning to the calling location. The example
you've seen of this was in the recursive Fibonacci MIPS program (Handout
#11: fib-s.asm); in this program, we're not using recursion and we had
no arguments, so we have less to restore.
lw $ra, 4($sp) # restore the return address
lw $fp, 0($sp) # restore the frame pointer
addu $sp, $sp, 8 # move the stack pointer down
jr $ra # go back to the instruction that
# called the subroutine
|
|||||||||||||||
| [7] | A Java
program has been constructed to present a very simple user interface.
The main program, Prob10.java, appears below:
public class Prob10
{
public static void main (String [] args)
When this
program is executed, the following appears: a JFrame containing a JButton
at the top and a JButton at the bottom.
public
myPanel()
and the method
actionPerformed(ActionEvent e).
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Prob10Frame extends JFrame
JButton circleButton = new JButton("Press to draw CIRCLE!");
JButton squareButton = new JButton("Press to draw SQUARE!");
MyPanel mp = new MyPanel();
boolean circleOrSquare = false;
int xValue, yValue;
public Prob10Frame(String name, int height, int width)
{
setTitle(name);
setSize(height, width);
setLocation(200, 200);
Container c = getContentPane();
ButtonListener bl = new ButtonListener();
circleButton.addActionListener(bl);
squareButton.addActionListener(bl);
c.add(mp, BorderLayout.CENTER);
c.add(squareButton, BorderLayout.SOUTH);
c.add(circleButton, BorderLayout.NORTH);
setVisible(true);
}
class MyPanel extends JPanel implements MouseListener
{
public MyPanel()
{
// missing code goes here! Part (A).
}
public void mouseClicked(MouseEvent me)
{
Graphics g = getGraphics();
xValue = me.getX();
yValue = me.getY();
if(circleOrSquare){
g.fillRect(xValue, yValue, 20, 20);
}
else{
g.fillOval(xValue, yValue, 20, 20);
}
}
public void mouseReleased(MouseEvent me)
{ }
public void mousePressed(MouseEvent me)
{ }
public void mouseEntered(MouseEvent me)
{ }
public void mouseExited(MouseEvent me)
{ }
}
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// missing code goes here! Part (B).
}
}
|
||||||||||||||
(A).
The main thing that needs to be in the MyPanel constructor is adding the
MouseListener - other than that, the panel is blank until the user clicks
it. Note also that the class itself is implementing the interface and
acting as its own listener. As required by the interface, all of the MouseListener
methods are included and defined. Your MyPanel constructor thus only needs
one line of code:
public MyPanel()
(B).
In the ButtonListener, you are asked to define actionPerformed(ActionEvent
e). You will need to look carefully at the rest of the code to see what
ought to go here. You know that you have two buttons in the Frame, which
add an object of this class as a listener, so your method must address
what happens when either button is clicked. If you look closely at the
mouseClicked() method in MyPanel, you'll see that the drawing of squares
or circles is determined by a variable named circleOrSquare. When
this variable is true, squares are drawn; otherwise, circles are drawn.
Your actionPerformed() method thus must manage this variable, so that
when the user clicks the squareButton, it is set to true, and the circleButton
will change it to false. This makes writing actionPerformed much easier:
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == squareButton){
circleOrSquare = true;
}
else{ // must be the circleButton
circleOrSquare = false;
}
}
Note that
when you look at the pictures of the program, the circles and squares
that are already drawn remain visible as new ones are added; therefore,
you will not want to call repaint(), because that would redraw the entire
panel and eliminate the previous figures. |
|||||||||||||||