练习1:
创建一个简单的类。在第二个类中,将一个引用定义为第一个类的对象。运用惰性初始化来实例化这个对象。
代码
public class TestConstructor {
//惰性初始化对象
HumanResource humanResource;
public static void main(String[] args) {
TestConstructor testConstructor = new TestConstructor();
testConstructor.print();
}
public void print() {
humanResource = new HumanResource(10);
//打印对象类型和地址
System.out.println(humanResource);
}
}
输出
HumanResource@4554617c
练习2:
从Detergent中继承产生一个新的类。覆盖scrub()并添加一个名为sterilize()的新方法。
代码
package testPackage;
public class Detergent {
public void scrub(){
System.out.println("scrub");
}
}
import testPackage.Detergent;
public class InheritDetergent extends Detergent {
@Override
public void scrub() {
System.out.println("InheritDetergent scrub");
}
public void sterilize() {
System.out.println("sterilize");
}
public static void main(String[] args) {
InheritDetergent inheritDetergent = new InheritDetergent();
inheritDetergent.scrub();
inheritDetergent.sterilize();
}
}
输出
InheritDetergent scrub
sterilize
练习3:
验证构建过程是向外扩散的。
代码
package testPackage;
public class Art {
public Art() {
System.out.println("Art");
}
}
package testPackage;
public class Drawing extends Art {
public Drawing() {
System.out.println("create Drawing");
}
}
package testPackage;
public class Cartoon extends Drawing {
public static void main(String[] args) {
Cartoon cartoon = new Cartoon();
}
}
输出
Art
create Drawing
练习4:
证明基类构造器:a.总是会被调用;b.在导出类构造器之前被调用。
代码
package testPackage;
public class Art {
public Art() {
System.out.println("Art");
}
}
package testPackage;
public class Drawing extends Art {
public Drawing() {
System.out.println("create Drawing");
}
}
package testPackage;
public class Cartoon extends Drawing {
public Cartoon() {
System.out.println("Cartoon");
}
public static void main(String[] args) {
Cartoon cartoon = new Cartoon();
}
}
输出
Art
create Drawing
Cartoon
由此可证。
练习5:
创建两个带有默认构造器(空参数列表)的类A和类B。从A中继承产生一个名为C的新类,并在C内创建一个B类的成员。不要给C编写构造器。创建一个C类的对象并观察其结果。
代码
package access.local;
public class AClass {
public AClass() {
System.out.println("create AClass");
}
}
package access.local;
public class BClass {
public BClass() {
System.out.println("create BClass");
}
}
package access.local;
public class CClass extends AClass {
BClass bClass = new BClass();
public static void main(String[] args) {
CClass cClass = new CClass();
}
}
输出
create AClass
create BClass
如果在CClass的构造器中添加打印,B的打印会在C之前。
如果采用惰性加载的方式,C打印会在B打印之前。
练习6:
验证:继承类构造器必须调用父类构造器。
练习7:
修改练习5,使A和B以带参数的构造器取代默认的构造器。为C写一个构造器,并在其中执行所有的初始化。
package access.local;
public class AClass {
public AClass(int i) {
System.out.println("create AClass");
}
}
package access.local;
public class BClass {
public BClass(int i) {
System.out.println("create BClass");
}
}
package access.local;
public class CClass extends AClass {
BClass bClass;
public CClass() {
super(1);
System.out.println("create CClass");
}
public static void main(String[] args) {
CClass cClass = new CClass();
cClass.bClass = new BClass(1);
}
}
输出
create AClass
create CClass
create BClass
练习8:
创建一个类,它仅有一个非默认构造器;再创建一个导出类,他带有默认构造器和非默认构造器。在导出类的构造器中调用基类的构造器。
代码
package access.local;
public class Game {
public Game(int integral) {
System.out.println(integral);
}
}
package access.local;
public class BoardGame extends Game {
public BoardGame() {
super(0);
}
public BoardGame(int integral) {
super(integral);
}
public static void main(String[] args) {
BoardGame boardGame = new BoardGame();
}
}
输出
0
练习9:
创建一个Root类,令其含有名为Component1、Commponent、Componen3的类的各一个实例。从Root中派生出一个类Stem,也含有上述各“组成部分”。所有的类都应带有可打印出类的相关信息的默认构造器。
代码
package access.local;
public class Root {
protected Component1 component1 = new Component1();
protected Component2 component2 = new Component2();
protected Component3 component3 = new Component3();
public Root() {
System.out.println("RootClass");
}
public static class Component1 {
public Component1() {
System.out.println("Component1");
}
}
public static class Component2 {
public Component2() {
System.out.println("Component2");
}
}
public static class Component3 {
public Component3() {
System.out.println("Component3");
}
}
public static class Stem extends Root {
public Stem() {
System.out.println("Stem");
}
public static void main(String[] args) {
Stem stem = new Stem();
}
}
}
输出
Component1
Component2
Component3
RootClass
Stem
练习10:
修改练习9,使每个类仅具有非默认的构造器。
代码
package access.local;
package access.local;
public class Root {
protected Component1 component1 = new Component1(66);
protected Component2 component2 = new Component2(66);
protected Component3 component3 = new Component3(66);
public Root(int i) {
System.out.println("RootClass" + i);
}
public static class Component1 {
public Component1(int i) {
System.out.println("Component1" + i);
}
}
public static class Component2 {
public Component2(int i) {
System.out.println("Component2" + i);
}
}
public static class Component3 {
public Component3(int i) {
System.out.println("Component3" + i);
}
}
public static class Stem extends Root {
public Stem(int i) {
super(i);
System.out.println("Stem" + i);
}
public static void main(String[] args) {
Stem stem = new Stem(666);
}
}
}
输出
Component166
Component266
Component366
RootClass666
Stem666
练习11
修改Detergent.java,让他使用代理。
代码
package testPackage;
public class Detergent {
public void scrub(){
System.out.println("scrub");
}
}
package testPackage;
public class ProtectedDetergent {
private final Detergent detergent = new Detergent();
public void scrub() {
detergent.scrub();
}
public static void main(String[] args) {
ProtectedDetergent protectedDetergent = new ProtectedDetergent();
protectedDetergent.scrub();
}
}
输出
scrub
练习12:
将一个适当的dispose()方法的层次结构添加到练习9的所有类中。
代码
package access.local;
public class Root {
protected Component1 component1 = new Component1(66);
protected Component2 component2 = new Component2(66);
protected Component3 component3 = new Component3(66);
public Root(int i) {
System.out.println("RootClass" + i);
}
public void dispose() {
System.out.println("Root dispose");
component1 = null;
component2 = null;
component3 = null;
}
public static class Component1 {
public Component1(int i) {
System.out.println("Component1" + i);
}
public void dispose() {
}
}
public static class Component2 {
public Component2(int i) {
System.out.println("Component2" + i);
}
public void dispose() {
}
}
public static class Component3 {
public Component3(int i) {
System.out.println("Component3" + i);
}
public void dispose() {
}
}
public static class Stem extends Root {
public Stem(int i) {
super(i);
System.out.println("Stem" + i);
}
@Override
public void dispose() {
super.dispose();
}
public static void main(String[] args) {
Stem stem = new Stem(666);
stem.dispose();
}
}
}
输出
Component166
Component266
Component366
RootClass666
Stem666
Root dispose
练习13:
创建一个类,它应带有一个被重载了三次的方法。继承产生一个新类,并添加一个该方法的新的重载定义,展示这四个方法在导出类中都是可以使用的。
代码
package testPackage;
public class RootOverload {
public void launch(int apple) {
System.out.println("RootOverload int apple");
}
public static class YourLaunch extends RootOverload {
public void launch(String banana) {
System.out.println("YourLaunch String banana");
}
}
public static class MyLaunch extends YourLaunch {
public void launch(char pair) {
System.out.println("MyLaunch pair");
}
}
public static class HisLaunch extends MyLaunch {
public void launch(boolean strawberry) {
System.out.println("MyLaunch strawberry");
}
public static void main(String[] args) {
HisLaunch hisLaunch = new HisLaunch();
hisLaunch.launch(1);
hisLaunch.launch("1");
hisLaunch.launch('1');
hisLaunch.launch(true);
}
}
}
输出
RootOverload int apple
YourLaunch String banana
MyLaunch pair
MyLaunch strawberry
练习14:
在Car.java中给Engine添加一个service()方法,并在main()中调用该方法。
is-a的关系使用继承来表达,has-a的关系则用组合来表达。
package access.local;
public class Engine {
public void service() {
System.out.println("service");
}
public static class Car {
public Engine engine = new Engine();
public static void main(String[] args) {
Car car = new Car();
car.engine.service();
}
}
}
输出
service
练习15:
在包中编写一个类,类应具备一个protected方法。在包外部,试着调用该protected方法并解释其结果。然后,从你的类中继承产生一个类,并从该导出类的方法内部调用该protected方法。
代码
package access.foreign;
public class TestProtectedClass {
protected void goTo() {
System.out.println("goto");
}
}
package access.local;
import access.foreign.TestProtectedClass;
public class PPClass extends TestProtectedClass {
public static void main(String[] args) {
PPClass ppClass = new PPClass();
ppClass.goTo();
}
}
引用
goto
练习16:
创建一个名为Amphibian的类。由此继承产生一个成为Frog的类。在基类中设置适当的方法。在main()中,创建一个Frog并向上转型至Amphibian,然后说明所有方法都可工作。
代码
package access.foreign;
public class Amphibian {
public void a() {
System.out.println("a");
}
public static class Frog extends Amphibian {
public void b() {
System.out.println("b");
}
public static void main(String[] args) {
Amphibian amphibian = new Frog();
amphibian.a();
((Frog) amphibian).b();
}
}
}
输出
a
b
练习17:
修改练习16,使用Frog覆盖基类中方法的定义(令新定义使用相同的方法特征签名)。留心main()中发生了什么。
代码
package access.foreign;
public class Amphibian {
public void a() {
System.out.println("a");
}
public static class Frog extends Amphibian {
public void b() {
System.out.println("b");
}
@Override
public void a() {
System.out.println("Frog a");
}
public static void main(String[] args) {
Amphibian amphibian = new Frog();
amphibian.a();
((Frog) amphibian).b();
}
}
}
输出
Frog a
b
练习18:
创建一个含有static final域和final域的类,说明两者间的区别。
代码
package access.local;
public class TestFinalClass {
static final int a = 1;
final int b;
public TestFinalClass() {
b = 1;
}
}
static final 必须定义时初始化,普通final可以运行时初始化。
练习19:
创建一个含有指向某对象的空白final引用的类。在所有构造器内部都执行空白final的初始化动作。说明Java确保final在使用前必须被初始化,且一旦被初始化即无法改变。
同上。
练习20:
展示@override注解可以解决本节中的问题。
略。重写方法加此注解可以有效保证重写的正确性,会在编译期报错。
练习21:
创建一个带final方法的类。由此继承产生一个类并尝试覆盖该方法。
略。无法复写,只能重新声明新方法。
练习22:
创建一个final类并尝试继承他。
不能继承,编译器报错。
练习23:
请证明加载类的动作仅发生一次。证明该类的第一个实体的创建或者对staitic成员的访问都有可能引起加载。
练习24:
在Beetle.java中,从Beetle类继承产生一个具体类型的“甲壳虫”。其形式与现有类相同,跟踪并解释其输出结果。
代码
package access.local;
public class Insect {
private int i;
protected int j;
private static int x1 = printInt("static Insect.x1 initialize.");
Insect() {
System.out.println("i = " + i + "j = " + j);
}
static int printInt(String s){
System.out.println(s);
return 4;
}
}
package access.local;
import access.local.Insect;
public class Beetle extends Insect {
private int k = printInt("Beetle.k initialized.");
private static int x2 = printInt("static Beetle.x2 initialized.");
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
public static void main(String[] args) {
System.out.println("Beetle start main");
Beetle beetle = new Beetle();
}
public static class BlueBeetle extends Beetle {
private static int x3 = printInt("static Beetle.x3 initialized.");
public BlueBeetle() {
System.out.println("BlueBeetle start.");
}
public static void main(String[] args) {
System.out.println("BlueBeetle start main");
BlueBeetle beetle = new BlueBeetle();
}
}
}
输出
static Insect.x1 initialize.
static Beetle.x2 initialized.
static Beetle.x3 initialized.
BlueBeetle start main
i = 0j = 0
Beetle.k initialized.
k = 4
j = 0
BlueBeetle start.
加载类时,静态对象总是从最根部的父类开始,向外扩散,构造方法亦是如此。