Exercises - Advanced Java Language Elements

  1. Explain the advantage of using generics and type parameters when constructing classes that represent a collection of things (e.g., stacks).

    With generics and type parameters, one does not need to write separate classes if one wishes to instantiate two or more collections that each collect a different type of object -- one can instead write a single class to implement the associated type of collection and have the client code specify the type of object a specific instance of that class should "collect".

  2. What methods does a class guarantee exist if it implements the Iterator interface?

    hasNext() and next()

  3. What method(s) does a class guarantee exist(s) if it implements the Iterable interface?

    iterator()

  4. What is the advantage of implementing the Iterable interface for a class that represents a collection of objects of the same type (e.g., stacks, queues, etc.)?

    One advantage is that one can use a "for-each" loop with objects of the resulting collection class. More generally, the Iterable interface allows one to iterate through the items in the collection in question.

  5. A class seeks to implement the Iterable interface by providing the iterator() method seen below. The method is intended to use an anonymous inner class to create the value to be returned. What should one type in the blank to complete the code?

    public Iterator<Item> iterator() {
        
        return ____________________________
            private int pos = 0;
            
            public boolean hasNext() {
                return nextPos < size;
            }
            
            public Item next() {
                return items[nextPos++];
            }
        };
    }

    new Iterator<Item>() {

  6. A class maintains an instance variable widgets of type Widget[] as shown below. The constructor must initialize this instance variable to be an array of length 10. What should one type in the blank to this end?

    public class TenThings<Widget> {
    
       Widget[] widgets;
    
       public TenThings() {
          widgets = _____________________;
    
             ⋮ 
       }
    
       ⋮
    }
    
    (Widget[] ) (new Object[10]);
  7. Consider the following code:

    import java.util.Iterator;
    
    public class ThingyMebob<Thing> {
        
        Thing[] things;
        
        public ThingyMebob() {
            things = new Thing[5];
        }
        
        public Iterator<Thing> iterator() {
            return _______________ {
                int pos = things.length-1;
                public boolean hasNext() {
                    return pos >= 0;
                }
                
                public Thing next() {
                    pos--;
                    return things[pos+1];
                }
            };
        }
        
        public void fill(Thing[] things) {
            for (int i =0; i < 5; i++)
                this.things[i] = things[i];
        }
        
        public static void main(String[] args) {
            ThingyMebob<String> bob = new ThingyMebob();
            String[] strs = {"a","b","c","d","e"};
            bob.fill(strs);
            for (String string : bob) 
                System.out.print(string);
        }
    }
    
    1. What code must be added in the blank to support for-each loops like the one in main?

    2. In addition to the code that must be added in the given blank addressed in the previous question, there are two other errors in the code above. Describe them both.

    1. new Iterator<Thing>()

    2. The class should implement the Iterable<Thing> interface, so add "implements Iterable<Thing>" after "public class ThingyMebob<Thing>".

      Also, generic array creation is not allowed in Java, so change "things = new Thing[10];" to "things = (Thing[]) (new Object[10]);"

  8. Bob finds he needs to store ordered pairs of various types of things for a given program (e.g., pairs of int values, of double values, of String objects, etc. Alice writes a OrderedPair class that she knows will work. Bob trusts her, but decides to test her OrderedPair class anyways -- so he writes the OrderedPairTest class below. He expects the indicated output, but keeps getting errors when he tries to run his class.

    public class OrderedPairTest {
    	
       public static void main(String[] args) {
    		
          OrderedPair<String> pair1 = new OrderedPair<String>("alice","bob");
          OrderedPair<int> pair2 = new OrderedPair<int>(5,7);
          OrderedPair<double> pair3 = new OrderedPair<double>(1.3,2.4);
    		
          System.out.println(pair1);
          System.out.println(pair2);
          System.out.println(pair3);
       }  
    }
    

    Expected output:

    (alice,bob)
    (5,7)
    (1.3,2.4)
    

    1. What is the source of Bob's errors -- what did he do incorrectly?

    2. Assuming that Bob wrote the OrderedPairTest class because he didn't trust her, Alice becomes irritated and deletes her OrderedPair code from his machine before he had a chance to fully understand it. Bob then begs for your help. Write the class OrderedPair, so that it behaves appropriately for Bob's code.

    1. Recall int and double are primitive types, but type parameters in Java must be reference types. He should use Integer and Double instead, respectively.

    2. public class OrderedPair<Item> {
          
          private Item x,y;
          
          public OrderedPair(Item x, Item y) {
              this.x = x;
              this.y = y;
          }
          
          public String toString() {
              return ("(" + x + "," + y + ")");
          }
      }