Problem 1: --------- a) Since a subclass necessarily has methods with all the same names as its parent (even if some are overriden), if a parent implements an interface then the subclass must as well. b) They *are* a weaker version of inheritance, but that's exactly what we need when working with dissimilar classes. If classes aren't closely related, then it doesn't make sense for one to inherit from another -- none of the inherited code would be useful -- but we can still get the benefits of a shared "contract" (e.g. polymorphism) by having the dissimilar classes implement a shared interface. Another advantage of interfaces is that Java allows a class to implement as many interfaces as it wants, while it can only extend a single parent class. Thus, for classes that have already extended a parent class, interfaces are the *only* way to add additional "contracts". Problem 2: --------- a) It's legal and would produce: Reporting: Hi, I'm Brad b) It's not legal. The variable x can only hold objects of type Thingy or its subclasses. The "contract" for x therefore includes methods (e.g. rename()) that Base doesn't have, so it wouldn't be safe to allow instances of Base to be stores in x. c) It's legal and would produce: I think my name is Eleanor d) The assignment statement is legal -- you can store an instance of a subclass of Base into the variable x -- but you're then restricted to the "contract" for Base: You can't call report() since report() isn't a method in Base, so the second line will produce a compile error. Problem 3: --------- a) Yes, it's polymorphic because the ArrayList passed as its input can contain different types of objects. (It can contain instances of Thingy or its subclasses.) b) No. Since the ArrayList is declared to hold objects of type Thingy it can hold instances of Thingy and/or its subclasses, but it can't hold instances of Base. The code in the body of the loop helps explain why: It tries to call rename() on the objects in the list, but Base objects don't HAVE a rename() method. c) There's a single FOR loop that traverses the entire list (it doesn't get to stop early), but there are some potential complications: The body of the IF statement inside the loop doesn't always run, and when it does run it calls get() and rename(), both of which involve a number of computational steps. We could assume that the body of the IF runs on every iteration as a worst case, but we can be more precise here since we know it runs on every OTHER iteration. It therefore only runs n/2 times for a list of length n. Once: i=0, println (2 steps) Once per: <, .size(), ++, %, == (Count .size() as one step since it's constant time.) That's 5 steps in the "once per iteration" category, plus the work in the body of the IF statement. We can see the code for rename(), and it's just one computational step. We know .get() is constant time, so let's count it as one step as well. Including the =, that's three steps inside the IF. Putting it all together we have: T(n) = 5n + 3(n/2) + 2 = 13n/2 + 2 d) Throwing away the lower-order terms and constants, we're left with: O(n) Any constant, c, greater than 13/2 will work. I'll pick c = 7. Now I need to figure out at what point 7n starts being >= 13n/2+2. Plugging in candidate values for n, I can see that it's not true until n gets to 4. (28 >= 28) I can therefore pick n0 = 4. Those two constants now prove that my O(n) isn't an underestimate: 7n >= 13n/2+2 for all n > 4. Problem 4: --------- Here's one solution. The print statements weren't required for full credit. public static BasicDie compareDice2(BasicDie die1, BasicDie die2) { int total1; try { total1 = rollRepeatedly(die1, 1000); } catch(Exception e) { System.out.println("First die is disqualified"); return die2; } int total2; try { total2 = rollRepeatedly(die2, 1000); } catch(Exception e) { System.out.println("Second die is disqualified"); return die1; } if (total1 > total2) { return die1; } else { return die2; } }