阅前声明:
http://blog.csdn.net/heimaoxiaozi/archive/2007/01/19/1487884.aspx
Exercise 8
/****************** Exercise 8 *****************
* Create a class as abstract without including
* any abstract methods, and verify that you
* cannot create any instances of that class.
***********************************************/
abstract
class NoAbstractMethods {
void f() { System.out.println("f()"); }
}
public
class E08_Abstract {
public static void main(String args[]) {
// Compile-time error: class is abstract,
// cannot be instantiated.
//! new NoAbstractMethods();
}
}
//+M java E08_Abstract
Exercise 9
/****************** Exercise 9 *****************
* Add class Pickle to Sandwich.java.
***********************************************/
class
Meal {
Meal() { System.out.println("Meal()"); }
}
class
Bread {
Bread() { System.out.println("Bread()"); }
}
class
Cheese {
Cheese() { System.out.println("Cheese()"); }
}
class
Lettuce {
Lettuce() { System.out.println("Lettuce()"); }
}
class
Pickle {
Pickle() { System.out.println("Pickle()"); }
}
class
Lunch extends Meal {
Lunch() { System.out.println("Lunch()");}
}
class
PortableLunch extends Lunch {
PortableLunch() {
System.out.println("PortableLunch()");
}
}
class
Sandwich extends PortableLunch {
Bread b = new Bread();
Cheese c = new Cheese();
Lettuce l = new Lettuce();
Pickle p = new Pickle();
Sandwich() {
System.out.println("Sandwich()");
}
}
public
class E09_Pickle {
public static void main(String args[]) {
new Sandwich();
}
}
//+M java E09_Pickle
**The output is:
Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Pickle()
Sandwich()
**
Note that the Pickle object is created in order, after the other member objects.
Exercise 10
/****************** Exercise 10 *****************
* Modify Exercise 6 so that it demonstrates the
* order of initialization of the base classes
* and derived classes. Now add member objects to
* both the base and derived classes, and show
* the order in which their initialization occurs
* during construction.
***********************************************/
class
Member {
private static int counter = 0;
private int id = ++counter;
public Member() {
System.out.println(
"Member constructor " + id);
}
}
class
Rodent3 {
Member m = new Member();
public Rodent3() {
System.out.println("Rodent constructor");
}
public void hop() {
System.out.println("Rodent hopping");
}
public void scurry() {
System.out.println("Rodent scurrying");
}
public void reproduce() {
System.out.println("Making more Rodents");
}
public String toString() {
return "Rodent";
}
}
class
Mouse3 extends Rodent3 {
Member m = new Member();
public Mouse3() {
System.out.println("Mouse constructor");
}
public void hop() {
System.out.println("Mouse hopping");
}
public void scurry() {
System.out.println("Mouse scurrying");
}
public void reproduce() {
System.out.println("Making more Mice");
}
public String toString() {
return "Mouse";
}
}
class
Gerbil3 extends Rodent3 {
Member m = new Member();
public Gerbil3() {
System.out.println("Gerbil constructor");
}
public void hop() {
System.out.println("Gerbil hopping");
}
public void scurry() {
System.out.println("Gerbil scurrying");
}
public void reproduce() {
System.out.println("Making more Gerbils");
}
public String toString() {
return "Gerbil";
}
}
class
Hamster3 extends Rodent3 {
Member m = new Member();
public Hamster3() {
System.out.println("Hamster constructor");
}
public void hop() {
System.out.println("Hamster hopping");
}
public void scurry() {
System.out.println("Hamster scurrying");
}
public void reproduce() {
System.out.println("Making more Hamsters");
}
public String toString() {
return "Hamster";
}
}
public
class E10_RodentInitialization {
public static void main(String args[]) {
new Hamster3();
}
}
//+M java E10_RodentInitialization
**The output for creating the Hamster3 object is:
Member constructor 1
Member constructor 2
Rodent constructor
Member constructor 7
Member constructor 8
Hamster constructor
**
The base class is initialized first, starting with the member objects in their order of definition, then the derived class starting with its member objects.
Exercise 11
/****************** Exercise 11 *****************
* Create a 3-level inheritance hierarchy. Each
* class in the hierarchy should have a
* finalize() method, and it should properly call
* the base-class version of finalize().
* Demonstrate that your hierarchy works
* properly.
***********************************************/
class
Base {
public Base() {
System.out.println("Base()");
}
protected void finalize() {
System.out.println("Base.finalize()");
}
}
class
Derived1 extends Base {
public Derived1() {
System.out.println("Derived1()");
}
protected void finalize() {
System.out.println("Derived1.finalize()");
super.finalize();
}
}
class
Derived2 extends Derived1 {
public Derived2() {
System.out.println("Derived2()");
}
protected void finalize() {
System.out.println("Derived2.finalize()");
super.finalize();
}
}
public class E11_ProperFinalization {
public static void main(String args[]) {
new Derived2();
System.gc();
}
}
//+M java E11_ProperFinalization
**The output is:
Base()
Derived1()
Derived2()
Derived2.finalize()
Derived1.finalize()
Base.finalize()
**
That the most-derived class must be finalized first, then the class it’s derived from, etc.; that is, that the order of finalization be in the reverse order of construction. This is important because the code in the most-derived class may depend on the existence of any of the elements of the base classes.
Exercise 12
/****************** Exercise 12 *****************
* Create a base class with two methods. In the
* first method, call the second method. Inherit
* a class and override the second method. Create
* an object of the derived class, upcast it to
* the base type, and call the first method.
* Explain what happens.
***********************************************/
class
TwoMethods {
public void m1() {
System.out.println("Inside m1, calling m2");
m2();
}
public void m2() {
System.out.println("Inside m2");
}
}
class
Inherited extends TwoMethods {
public void m2() {
System.out.println("Inside Inherited.m2");
}
}
public
class E12_MethodCalls {
public static void main(String args[]) {
TwoMethods x = new Inherited();
x.m1();
}
}
//+M java E12_MethodCalls
**The output is:
Inside m1, calling m2
Inside Inherited.m2
**
The first method isn’t overriden, but it calls the second method, which is. Java will always use the most-derived method it can find for the object type. If you’re not thinking about this, it can be surprising. However, it can also be very powerful – this is the way the Template Method design pattern works (see Thinking in Patterns, downloadable from www.BruceEckel.com).
Exercise 13
/****************** Exercise 13 *****************
* Create a base class with an abstract print()
* method that is overridden in a derived class.
* The overridden version of the method prints
* the value of an int variable defined in the
* derived class. At the point of definition of
* this variable, give it a nonzero value. In the
* base-class constructor, call this method. In
* main(), create an object of the derived type,
* and then call its print() method. Explain the
* results.
***********************************************/
class
BaseWithPrint {
public BaseWithPrint() {
print();
}
public void print() {
System.out.println("BaseWithPrint.print");
}
}
class
DerivedWithPrint extends BaseWithPrint {
int i = 47;
public void print() {
System.out.println("i = " + i);
}
}
public
class E13_Initialization {
public static void main(String args[]) {
DerivedWithPrint dp = new DerivedWithPrint();
dp.print();
}
}
//+M java E13_Initialization
**The output is:
i = 0
i = 47
**When the base-class constructor is called, the derived-class initialization has not yet been run, so the value of i is the default which comes from wiping the bits of the object to zero right after the storage has been allocated.
**This exercise is intended to point out the dangers of calling methods inside of constructors. Although it is certainly justified at times, you should be careful because these methods may depend on some derived initialization that hasn’t yet taken place. The safest approach is to do as little as possible to set the object into a known good state, and then do any other operations separately from the constructor.
Exercise 14
/****************** Exercise 14 *****************
* Following the example in Transmogrify.java,
* create a Starship class containing an
* AlertStatus reference that can indicate three
* different states. Include methods to change
* the states.
***********************************************/
class
AlertStatus {
private String status;
// Can only use the objects given in
// this class; cannot create others:
private AlertStatus(String istatus) {
status = istatus;
}
public String getStatus() {
return status;
}
public static final AlertStatus
RED = new AlertStatus("Red"),
YELLOW = new AlertStatus("Yellow"),
GREEN = new AlertStatus("Green");
}
class
Starship {
private AlertStatus status = AlertStatus.GREEN;
public void setStatus(AlertStatus istatus) {
status = istatus;
}
public String toString() {
return status.getStatus();
}
}
public
class E14_Starship {
public static void main(String args[]) {
Starship eprise = new Starship();
System.out.println(eprise);
eprise.setStatus(AlertStatus.YELLOW);
System.out.println(eprise);
eprise.setStatus(AlertStatus.RED);
System.out.println(eprise);
}
}
//+M java E14_Starship
**Since there are only three different variations of the AlertStatus object needed and they are all effectively constant, I used the “enumeration” idiom to create a fixed number of objects, making the constructor private to prevent the creation of any more.
**The Starship class holds a reference to an AlertStatus object, and the setStatus( ) method allows you to change this reference, effectively changing the behavior of the Starship.
**The output is:
Green
Yellow
Red
**The reason this is an example of the State pattern is that the object behaves differently (when the toString( ) method is implicitly called, in the example above) depending on what state it is in.
Exercise 15
/****************** Exercise 15 *****************
* Create an abstract class with no methods.
* Derive a class and add a method. Create a
* static method that takes a reference to the
* base class, downcasts it to the derived class,
* and calls the method. In main(), demonstrate
* that it works. Now put the abstract
* declaration for the method in the base class,
* thus eliminating the need for the downcast.
***********************************************/
abstract
class NoMethods {}
class
Extended1 extends NoMethods {
public void f() {
System.out.println("Extended1.f");
}
}
abstract
class WithMethods {
abstract public void f();
}
class
Extended2 extends WithMethods {
public void f() {
System.out.println("Extended2.f");
}
}
public
class E15_AbstractBase {
public static void test1(NoMethods nm) {
// Must downcast to access f():
((Extended1)nm).f();
}
public static void test2(WithMethods wm) {
// No downcast necessary:
wm.f();
}
public static void main(String args[]) {
NoMethods nm = new Extended1();
test1(nm);
WithMethods wm = new Extended2();
test2(wm);
}
}
//+M java E15_AbstractBase
**Both versions are shown here, and in test1( ) you can see how a downcast is necessary in order to call f( ) (take out the downcast if you don’t believe it). In test2( ), no downcast is necessary because the method f( ) is defined in the base class.
**The output is:
Extended1.f
Extended2.f