源码地址:https://github.com/yangxian1229/ThinkingInJava
练习1:创建一个简单的类。在第二个类中,将一个引用定义为第一个类的对象。运用惰性初始化来实例化这个对象。
package ch7;
import static net.mindview.util.Print.*;
class Simple{
String s;
public Simple(String si){ s = si;}
public String toString(){ return s;}
public void setString(String sNew){ s = sNew;}
}
class Second{
Simple simple;
String s;
public Second(String si){
s = si; //'simple' not initialized
}
public void check(){
if(simple == null)
print("not initialized");
else
print("initialized");
}
private Simple lazy(){
if(simple == null){
print("Creating Simple");
simple = new Simple(s);
}
return simple;
}
public Simple getSimple(){ return lazy();}
public String toString(){
return lazy().toString();
}
public void setSimple(String sNew){
lazy().setString(sNew);
}
}
public class E01 {
public static void main(String[] args) {
Second second = new Second("Init String");
second.check();
print(second.getSimple());
second.check();
print(second);//toString() call
second.setSimple("New String");
print(second);
}
}
The Simple class has some data and methods. The Second class performs lazy initialization through the lazy( ) method, which creates (if it hasn’t been) the Simple object and then returns it. The lazy( ) method is called by all the other methods to access the Simple object.
We added print statements to show when initialization occurs, and that it happens only once.
练习2:从Detergent中继承产生一个新的类。覆盖scrub()并添加一个名为sterilize()的新方法。
练习3:略。
练习4:略。
练习5:创建两个带有默认构造器(空参数列表)的类A和类B。从A类中继承产生一个名为C的新类,并在C内创建一个B类成员。不要给C编写构造器。创建一个C类对象并观察其结果。
练习6:证明:“调用基类构造器必须是你在导出类构造器中要做的第一件事。”
练习7:修改练习5,使A和B以带参数的构造器取代默认的构造器。为C写一个构造器,并在其中执行所有的初始化。
练习8:创建一个基类,它仅有一个非默认构造器;再创建一个导出类,它带有默认构造器和非默认构造器。在导出类的构造器中调用基类的构造器。
练习9:创造一个Root类,令其含有名为Component1,Component2,Component3的类的各一个实例。从Root中派生一个类Stem,也含有上述各“组成成分”。所有的类都应带有可打印的相关信息的的默认构造器。
练习10:修改练习9,使每个类都仅具有非默认的构造器。
练习11:修改Detergent.java,让它使用代理。
练习12:将一个适当的dispose()方法的层次结构添加到练习9的所有类中。
Remember, it’s important to call the dispose( ) methods in the reverse order of initialization.
练习13:创建一个类,它应带有一个被重载了三次的方法。继承产生了一个新类,并添加一个该方法的新的重载定义,展示这四个方法在导出类中都是可以使用的。
练习14:在Car.java中给Engine添加一个service()方法,并在main()中调用该方法。
练习15:在包中编写一个类,类应具备一个protected方法。在包外部,试着调用该protected方法并解释其结果。然后,从你的类中继承产生一个类,并从该导出类的方法内部调用该protected方法。
练习16:创建一个名为Amphibian的类。由此集成产生一个称为Frog的类。在基类中设置适当的方法。在main()中,创建一个Frog向上转型至Amphibian,然后说明所有方法都可以工作。
练习17:修改练习16,使Frog覆盖基类中的方法的定义(令新定义使用相同的方法特征签名)。请留心main()中都发生了什么。
练习18:创建一个含有static final域和final域的类,说明二者间的区别。
package ch7;
import static net.mindview.util.Print.*;
class SelfCounter{
private static int count;
private int id = count++;
public String toString(){return "SelfCounter "+id;}
}
class WithFinalFields{
final SelfCounter scf = new SelfCounter();
static final SelfCounter sscf = new SelfCounter();
public String toString(){
return "scf = "+scf+"\nsscf = "+sscf;
}
}
public class E18 {
public static void main(String[] args) {
print("First object:");
print(new WithFinalFields());
print("Second object:");
print(new WithFinalFields());
}
}/* Output:
First object:
scf = SelfCounter 1
sscf = SelfCounter 0
Second object:
scf = SelfCounter 2
sscf = SelfCounter 0
*///:~
Because class loading initializes the static final, it has the same value in both instances of WithFinalFields, whereas the regular final’s values are different for each instance.
练习19:创建一个含有指向某对象的空白final引用的类。在所有构造器内部都执行空白final的初始化动作。说明Java确保final在使用前必须初始化,且一旦被初始化即无法改变。
练习20:展示@Override注解可以解决本节问题。
练习21:创建一个带final方法的类。由此继承产生一个类并尝试覆盖该方法。
练习22:创建一个final类并试着继承它。
练习23:请证明加载类的动作近发生一次。证明该类的第一个实体的创建或者对static成员的访问都有可能引起加载。
package ch7;
import static net.mindview.util.Print.print;
class LoadTest{
//The static clause is executed upon class loading:
static{
print("Loading LoadTest");
}
static void staticMember(){}
}
public class E23 {
public static void main(String[] args) {
print("Creating an object");
new LoadTest();
print("Calling static member");
LoadTest.staticMember();
}
}/* Output:
Creating an object
Loading LoadTest
Calling static member
*///;~
Now modify the code so object creation occurs before the static member call to see that object creation loads the object. Remember, a constructor is a static method, even though you don’t define it using the static keyword.
练习24:在Beetle.java中,从Beetle类继承产生一个具体类型的“甲壳虫”。其形式与现有类相同,跟踪并解释其输出结果。