源代码地址:https://github.com/yangxian1229/ThinkingInJava
练习1:编写一个名为Outer的类,它包含一个名为Inner的类。在Outer中添加一个方法,它返回一个Inner类型的对象。在main()中创建并初始化一个指向某个Inner对象的引用。
练习2:创建一个类,它持有一个String,并且有一个显示这个String的toString()方法。将你的新类的若干个对象添加到一个Sequence对象中,然后显示它们。
练习3:修改练习1,使得Outer类包含一个private String域(由构造器初始化),而Inner包含一个显示这个域的toString()方法。创建一个Inner类型的对象并显示它。
练习4:在Sequence.SequenceSelector类中增加一个方法,它可以生成对外部类Sequence的引用。
练习5:创建一个包含内部类的类,在另一个独立的类中,创建此内部类的实例。
package ch10;
import ch10.E05A.Inner;
class E05A{
public class Contents{
Contents(){System.out.println("Contents");}
}
static class Inner{
Inner(){System.out.println("Inner");}
}
}
public class E05 {
public static void main(String[] args) {
E05A ea = new E05A();
E05A.Contents ec = ea.new Contents();
//static innerclass
E05A.Inner ei = new Inner();
}
}/* Output:
Contents
Inner
*///:~
练习6:在第一个包中创建一个至少有一个方法的接口。然后在第二个包内创建一个类,在其中增加一个protected的内部类以实现那个接口。在第三个包中,继承这个类,并在一个方法中返回该protected内部类的对象,在返回的时候向上转型为第一个包中的接口类型。
练习7:创建一个含有private域和private方法的类。创建一个内部类,它有一个方法可用来修改外围类的域,并调用外围类的方法。在外围类的另一个方法中,创建此内部类的对象,并且调用它的方法,然后说明对外围类对象的影响。
练习8:确定外部类是否可以访问其内部类的private元素。
答:可以。
练习9:创建一个至少有一个方法的接口。在某个方法内定义一个内部类以实现此接口,这个方法返回对此接口的引用。
练习10:重复前一个练习,但将内部类定义在某个方法的一个作用域内。
练习11:创建一个private内部类,让它实现一个public接口。写一个方法,它返回一个指向此private内部类的实例的引用,并将此引用向上转型为该接口类型。通过尝试向下转型说明此内部类完全隐藏了。
练习12:重复练习7,这次试用匿名内部类。
练习13:重复练习9,这次试用匿名内部类。
练习14:修改interfaces/HorrorShow.java,用匿名类实现DangerousMonster和Vampire。
练习15:创建一个类,它有非默认的构造器(即需要参数的构造器),并且没有默认构造器。创建第二个类,它包含一个方法,能够返回对第一个类的对象的引用。通过写一个继承自第一个类的匿名内部类,来创建一个返回对象。
package ch10;
class E15A{
E15A(int i){
System.out.println("E15A:"+i);
}
void print(){
System.out.println("Hello world!");
}
}
class E15B{
public E15A f(int i){
return new E15A(i){};
}
public E15A f2(int i){
return new E15A(i){
void print(){
System.out.println("E15B f2()");
}
};
}
}
public class E15 {
public static void main(String[] args) {
E15A ea = new E15B().f(3);
ea.print();
E15A ea2 = new E15B().f2(233);
ea2.print();
}
}/* Output:
E15A:3
Hello world!
E15A:233
E15B f2()
*///:~
练习16:修改第9章中练习18的解决方案,让它使用匿名内部类。
练习17:修改第9章中练习19的解决方案,让它使用匿名内部类。
练习18:创建一个包含嵌套的类。在main()中创建其内部类的实例。
练习19:创建一个包含了内部类的类,而此内部类又包含有内部类。使用嵌套类重复这个过程。注意编译器生成的.class文件的名字。
package ch10;
public class E19 {
class Inner1{
class Inner2{
void f(){}
}
Inner2 makeInner2(){return new Inner2();}
}
Inner1 makeInner1(){return new Inner1();}
static class E19A{
static class E19B{
public void printB(){
System.out.println("E19B Hello world!");
}
}
public void printA(){
System.out.println("E19A Hello world!");
}
}
public static void main(String[] args) {
new E19.E19A().printA();
new E19.E19A.E19B().printB();
E19 e = new E19();
E19.Inner1 i1 = e.makeInner1();
E19.Inner1.Inner2 i2 = i1.makeInner2();
}
}/* Output:
E19A Hello world!
E19B Hello world!
*///:~
练习20:创建一个包含嵌套类的接口,实现此接口并创建嵌套类的实例。
练习21:创建一个包含嵌套类的接口,该嵌套类中有一个static方法,它将调用接口中的方法并显示结果。实现这个接口,并将这个实现的一个实例传递给这个方法。
练习22:实现Sequence.java中的reverseSelector()方法。
练习23:创建一个接口U,它包含三个方法。创建第一个类A,它包含一个方法,在此方法中通过创建一个匿名内部类,来生成指向U的引用。创建第二个类B,它包含一个由U构成的数组。B应有几个方法,第一个方法可以接受对U的引用并存储到数组中;第二个方法将数组中的引用设为null;第三个方法遍历此数组,并在U中调用这些方法。在main()中,创建一组A的对象和一个B的对象。用那些A类对象所产生的U类型的引用填充B对象的数组。使用B回调所有A的对象。再从B中移除某些U的引用。
练习24:练习25:看完22章回来看。
练习26:创建一个包含内部类的类,此内部类有一个非默认的构造器(需要参数的构造器)。创建另一个也包含内部类的类,此内部类继承自第一个内部类。
package ch10;
class E26A{
class E26B{
E26B(int i){
System.out.println("E26B");
}
}
}
public class E26 extends E26A.E26B{
E26(E26A ea){
ea.super(1);
System.out.print("E26");
}
public static void main(String[] args) {
E26 e = new E26(new E26A());
}
}/* Output:
E26B
E26
*///:~