源码地址:https://github.com/yangxian1229/ThinkingInJava
练习1:创建一个类,它包含一个未初始化的String引用。验证该引用被Java初始化成了null。
练习2:创建一个类,它包含一个在定义时就被初始化的String域,以及另个一个通过构造器初始化的String域。这两种方式有何差异。
package ch5;
class StringTest1{
String s="aaaa";
String s2;
StringTest1(String s1){
s2 = s1;
}
}
public class E02 {
public static void main(String[] args) {
StringTest1 st = new StringTest1("bbbb");
System.out.println(st.s);
System.out.println(st.s2);
}
}
The s1 field is initialized before the constructor is entered; technically, so is the s2 field, which is set to null as the object is created. The more flexible s2 field lets you choose what value to give it when you call the constructor, whereas s1 always has the same value.
练习3:创建一个带默认构造器(即无参构造器)的类,在构造器中打印一条信息。为这个类创建一个对象。
练习4:为前一个练习中的类添加一个重载构造器,令其接受一个字符串参数,并在构造器中把你自己的消息和接收的参数一起打印出来。
练习5:创建一个名为Dog的类,它具有重载的bark()方法。此方法应根据不同的基本数据类型进行重载,并根据调用的版本,打印出不同类型的狗吠(barking),咆哮(howling)等信息。
练习6:修改前一个练习的程序,让两个重载方法各自接受两个类型的不同参数,但二者顺序相反。验证其是否工作。
练习7:创建一个没有构造器的类,并在main()中创建其对象,用以验证编译器是否真的自动加入了默认构造器。
练习8:略。
练习9:编写具有两个(重载)构造器的类,并在第一个构造器中通过this调用第二个构造器。
练习10:编写具有finalize()方法的类,并在方法中打印消息。在main()中为该类创建一个对象。试解释这个程序的行为。
package ch5;
public class E10 {
protected void finalize(){
System.out.println("finalized");
}
public static void main(String[] args) {
new E10();
}
}///:~
You probably won’t see the finalizer called because the program doesn’t usually generate enough garbage for the collector to run.
练习11:修改前一个练习的程序,让你的finalize()总会被调用。
package ch5;
public class E11 {
protected void finalize(){
System.out.println("finalized");
}
public static void main(String[] args) {
new E11();
System.gc();
System.runFinalization();
}
}///:~
Calling System.gc( ) and System.runFinalization( ) in sequence will probably but not necessarily call your finalizer (The behavior of finalize has been uncertain from one version of JDK to another.) The call to these methods is just a request; it doesn’t ensure the finalizer will actually run. Ultimately, nothing guarantees that finalize( ) will be called.
练习12:编写一个名为Tank的类,此类的状态可以是“满的”或“空的”。其终结条件是:对象被清理时必须处于空状态。请编写finalize()以检验终结条件是否成立。在main()中测试Tank可能发生的几种使用方式。
package ch5;
import static net.mindview.util.Print.*;
class Tank{
static int count;
int id = count++;
boolean full;
public Tank(){
print("Tank "+id+" is created.");
full = true;
}
public void empty(){
full = false;
}
protected void finalize(){
if(full)
print("Error : Tank "+id+" must be empty at cleanup.");
else
print("Tank "+id+" cleaned up ok.");
}
public String toString(){
return "Tank "+id;
}
}
public class E12 {
public static void main(String[] args) {
new Tank().empty();
//Don't empty the seconed one
new Tank();
System.gc();
System.runFinalization();
}
}/* Output:
Tank 0 is created.
Tank 1 is created.
Tank 0 cleaned up ok.
Error : Tank 1 must be empty at cleanup.
*///:~
We created no references to the two instances of type Tank, because those references would be in scope when System.gc( ) was called so they wouldn’t be cleaned up, thus they wouldn’t be finalized. Another option is to set references to zero when you want them to be garbage-collected. Modify the above example to try this method.
You can never be sure finalizers will be called, so their utility is limited. A finalizer can, for example, check the state of objects when it does run, to ensure they’ve been cleaned up properly.
练习13:略。
练习14:编写一个类,拥有两个静态字符串域,其中一个在定义处初始化,另一个在静态块中初始化。现在,加入一个静态方法用以打印出两个字段值。请证明它们会在被使用之前完成初始化动作。
练习15:编写一个含有字符串域的类,并采用实例初始化方式进行初始化。
练习16:创建一个Strng对象数据,并为每一个元素都赋值一个String。用for循环来打印该数组。
练习17:创建一个类,它有一个接受一个String参数的构造器。在构造阶段,打印该参数。创建一个该类的对象引用数组,但是不实际去创建对象赋值给该数组。当运行程序时,请注意来自对该构造器的调用中对初始化消息是否打印了出来。
package ch5;
public class E17 {
E17(String s1){
System.out.println("HAHA"+s1);
}
public static void main(String[] args) {
E17[] e17s = new E17[4];
}
}
This code creates only the array, not the objects that go into it. You don’t see initialization messages in E17’s constructors because no instances of that class exist.
练习18:通过创建对象引用数组,从而完成前一个练习。
练习19:写一个类,它接受一个可变参数的String数组。验证你可以向该方法传递一个用逗号分隔的String列表,或是一个String[]。
练习20:创建一个使用可变参数列表而不是普通的main()语法的main()。打印所产生的args数组的所有元素,并用各种不同数量的命令行参数来测试它。
练习21:创建一个enum,它包含纸币中最小面值的6中类型。通过values()循环并打印每一个值及其ordinal()。
练习22:在前面的例子中,为enum写一个switch语句,对于每一个case,输出该特定货币的描述。
package ch5;
import static net.mindview.util.Print.*;
enum PaperCurrencyTypes{
ONE,TWO,FIVE,TEN,TWENTY,FIFTY
}
public class E21_E22 {
static void describe(PaperCurrencyTypes pct){
printnb(pct+" has a portrait of ");
switch (pct) {
case ONE:print("George Washington");
break;
case TWO:print("Thomas Jefferson");
break;
case FIVE: print("Abraham Lincoln");
break;
case TEN: print("Alexander Hamilton");
break;
case TWENTY: print("Andrew Jackson");
break;
case FIFTY: print("U.S. Grant");
break;
default: print("ERROR");
break;
}
}
public static void main(String[] args) {
for(PaperCurrencyTypes s:PaperCurrencyTypes.values()){
//21
//print(s+", ordinal "+s.ordinal());
describe(s);
}
}
}/* Output:
ONE has a portrait of George Washington
TWO has a portrait of Thomas Jefferson
FIVE has a portrait of Abraham Lincoln
TEN has a portrait of Alexander Hamilton
TWENTY has a portrait of Andrew Jackson
FIFTY has a portrait of U.S. Grant
*///:~