1.组合和继承,两种代码重用机制。2.当创建一个类时,总是在继承,因此,除非已明确指出要从其他类中继承,否在就是在隐式的从Java的标准根类Object进行继承。3.String:+ / +=4.调用父类的方法,用super.f(),否在如果在子类覆写的f方法中调用f的话,则会产生递归;5.继承并不只是复制基类的接口。当创建了一个导出类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建的对象是一样的。二者区别在于,后者来自外部,而基类的子对象被包装在导出类对象内部。 ->对基类子对象的正确初始化至关重要,而且仅有一种方法保证这一点。在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需要的所有知识和能力。Java会自动在导出类的构造器中插入对基类构造器的引用。 ->如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须使用关键字super显示的编写调用基类构造器的语句,并且配以适当的参数列表。 ->调用基类构造器必须是在你导出构造器中要做的第一件事情。[否在编译器报错]6.第三种关系称为代理,Java并没有提供对它的直接支持。这是继承与组合之间的中庸之道,因为我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的所有方法(就像继承)。7.有时候类可能在生命周期内执行一些必要的清理活动。因为你并不知道垃圾回收器何时被调用,或者它是否会调用。因此,如果你想要某个类清理一些东西,就必须显示的编写一个特殊方法来做这件事,并确保客户端程序员知晓他们必须调用这一方法。【必须将这一清理动作置于finaly子句中,以预防异常的出现】8.清理方法(dispose)中,还必须注意对基类清理方法和成员对象清理方法的调用顺序,以防止某个子对象依赖于另一个子对象的情形。一般而言,所采用的形式应该与C++编译器在其析构函数上所施加的形式相同:首先,执行类的所有特定的清理动作,其顺序同生成顺序相反(通常这就要求基类元素仍然存活),然后调用基类的清理方法。 注:C++构造函数和析构函数顺序 1.构造函数:基类依次调用->类内部成员声明的顺序构造->派生类构造。 2.析构函数:与析构函数顺序相反,编译器用栈实现。 [个人认为因为类内部成员的声明顺序表明对象之间的依赖情形,如A先声明,表明A可能会被其他对象依赖,所以在析构的时候要最后析构] 许多情况下,清理并不是问题,仅需让垃圾回收器完成该动作就行。但当必须亲自处理清理时,就的多做努力并多加小心。因为一旦涉及垃圾回收,能够信赖的事就不会很多了。垃圾回收器可能永远也无法调用,即使被调用,它也可能以任何它想要的清理顺序来回收对象。最好的办法除了内存以外,不能依赖垃圾回收器去做任何事情。如果需要清理,最好是编写自己的清理方法,不过不要使用finalize().9.名称屏蔽: 1.如果Java的基类拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法名称并不会屏蔽其在基类中的任何版本。(这一点与C++不同),因此无论是在该层还是它的基类对方法进行重新定义,重载机制都可以正常工作。 注:Java这样做,看上去也令人迷惑不解,这也是C++为什么不允许这样做的原因所在一防止你可能会犯错误。10.@Override注解,当你想要覆写某个方法时,可以选择添加这个注解,在你不留心重载而非覆写了该方法时,编译器会报错。11.组合与继承之间选择: 1.二者都允许在新的类中放置子对象,组合是显示的这样做,而继承是隐式的做。 2.组合技术通常用于想在新类中使用现有类的功能而非它的接口的情形,即在新类中嵌入某个对象,让其实现所需要的功能。->新类中嵌入一个现有类的private对象。 3.在继承的时候,是有某个现有类,并开发它的一个特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。 4.is-a(是一个)的关系是用继承来描述的;而has-a(有一个)的关系是用组合来表达的。12.protected:就类用户而言,这是private的,但对于任何继承于此类的导出类或者任何位于同一个包的类来说,它却是可以访问的;protected也提供了包内访问权限; 注:尽管可以创建protected域,不过最好的方式还是将域保持为private,你应当一直保留“更改底层实现的权利”;然后通过protected方法来控制类的继承者的访问权限。13.为新的类提供方法并不是继承技术最重要的一方面,其最重要的方面是用来表现新类和基类之间的关系。这种关系可以用“新类是现有类的一种类型”这句话加以概括。 ->语言支撑,由于继承 可以确保基类中所有的方法在导出类中也同样有效,所以能够像基类发送的所有信息同样也可以向导出类发送->编译器支持->向上转型 ->向上转型,因为传统的类继承图的绘制方法,根置于页面的顶端,然后逐渐向下。导出类转成基类,在继承图是向上移动的,所以一般称为向上转型。 ->因为向上转型是一个从较专用类型向较通用类型转换,所以总是很安全的。也就是说,导出类是基类的一个超集。它可能比基类含有更多的方法,但它必须至少具备基类中所含有的方法。在向上转型的过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取他们(不能访问他们/赢得这些方法)。这就是为什么编译器在“未曾明确表示转型”或“未曾指定特殊标记”的前提下,仍然允许向上转型的原因。14.面向对象编程中,生成和使用程序代码最有可能采用的方法就是直接将数据和方法包装进一个类中,并使用该类的对象。也可以运用组合技术使用现有类来开发新的类,而继承技术其实并不是太常用。应当慎用这一技术,其使用场合仅限于你确信使用该技术有效的情况。到底是使用组合还是继承,一个最清晰的判断方法就是问一问是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必要的;但如果不需要,则应当好好考虑自己是否需要继承。15.可能用到final的三种情况:数据,方法,和类 final,通常是指无法改变的;不想改变可能出于两种理由,设计或效率。 1.数据的恒定不变,如:一个永不改变的编译时常量(带有恒定初始值);一个在运行时被初始化的值,而你不希望它被改变;对于基本类型,final使数值恒定不变,而用于对象引用,final使引用恒定不变;一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而对象自身确实可以被修改的。这一对象同样适用于数组,它也是对象(另一种引用)。 2.定义为static,则强调只有一份;定义为final,则说明它是一个常量。 3.不能因为某数据是final的就认为在编译时可以知道它的值,在运行时也可动态生成,如利用Random随机。 4.空白final:所谓空白final是指被声明为final却又未给定初值的域。无论什么情况,编译器都确保空白final在使用前必须被初始化。但是空白final在关键字final的使用上提供了更大的灵活性。为此,一个类中final域就可以做到根据对象有所不同,却又保持其恒定不变的特性。[即在不同的构造函数来初始化final] 必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因。 5.final参数:Java允许在参数列表中以生命的方式将参数声明为final,这意味着你无法在方法中更改参数引用所指向的对象。 ->当基本类型的参数被指定为final的时候,你可以读参数,不过却无法修改参数.这一特性主要用来向匿名内部类传递数据; 6.final方法:使用final方法的原因有两个:第一个原因是把方法锁定。以防止任何继承类修改它的含义。确保在继承中使方法行为保持不变,并且不会被覆盖。过去建议使用final方法的原因是效率。在java早期实现中,如果将一个方法指明为final的话,就是同意编译器将针对对该方法的所有调用都转为内嵌调用。当编译器发现一个final方法调用命令时,它会根据自己的谨慎判断,跳过插入程序代码这种正常方式而执行方法调用机制(将参数压入栈,跳至方法代码处并执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来代替方法调用。这种将消除方法调用的开销。当然,如果一个方法很大, 你的程序代码就会膨胀,因为可能看不到内嵌带来的任何性能上的提高。因为所带来的性能的提高会因为花费于方法内的时间量而被缩减。在最近的Java版本中,特别是hotspot技术可以探测到这种情况,并优化去掉这些效率反而降低的额外的内嵌调用,因此不再需要使用final方法来进行优化了。事实上,这种做法正在逐渐的受到劝阻。在使用javase5/se6的时候,应该让编译器和JVM去处理效率问题,只有在想明确禁止覆盖的时候,才将方法设为final的。 7.final和private关键字,类中所有private方法都隐式的指定为final.由于无法取用private,所以也就无法覆盖它。可以对private方法添加final修饰词,但是这并不能给该方法添加任何额外的意义。如果你试图覆盖private方法(隐含是final的),似乎是奏效的;不过:因为:“覆盖”只是在某方法是基类的接口的一部分才会出现;即,必须将一个对象向上转型为它的基本类型并调用相同的方法。如果某方法为private,它就不是基类接口的一部分。如果在导出类中以相同的名称生成一个方法的话,此时你并没有覆盖该方法,而只是生成了一个新的方法。由于private方法无法触及而且能有效隐藏,所以除了把它看做是因为它归属类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。 8.final类:当将某个类的整体定义为final时,(通常将关键字定义于它的定义之前),就表明了你不打算继承该类,而且也不允许别人这么做。换句话说,出于某种考虑,你对该类的设计不需要任何变动,或出于安全的考虑,你不希望它有子类。 注:final类的域可以根据个人意愿的选择为是或者不是final,无论类是否被定义为final,系统的规则都适用于定义为final的域。然而由于final类禁止继承,所以final类的所有方法都隐式指定是final的,因为无法覆盖他们。final类中可以给方法添加final修饰词,不过不会增添任何意义。16. Vector:1.许多方法为final,无法继承并覆盖2.Statck继承Vector,逻辑上不合理3.方法同步 ->ArrayList Hashtable:1.竟然没有final方法2.同步->HashMap 上面的两个例子说明Java标准程序库也有一些粗糙的设计。17.每个类的编译代码都存在于它自己的独立文件中。该文件只在需要使用程序代码时才会加载。一般来说,类的代码在初次使用时才加载。这通常是指加载发生于创建类的第一个对象之时,但是当访问static时,也会发生加载。初次使用之处也是static初始化发生之处。所有的static对象和static代码都会在加载时依程序中的顺序,即定义类时的书写顺序而依次初始化。当然,定义为static的东西只会被初始化一次。(构造器也是static方法,尽管static关键字没有显示的写出来,因此更准确的讲,类是在其任何static成员被访问时加载的)18.总结: 1.继承和组合都能从现有类型生成新类型。组合一般是将现有类型作为新类型底层实现的一部分加以复用,而继承复用的是接口。在使用继承时,由于导出类具有基类接口,因此它可以向上转型至基类,这对多态至关重要。尽管面向对象编程对继承极力强调,但在开始一个设计时,一般应优先选择使用组合或者可能是代理,只有在确实必要时才使用继承。因为组合更具灵活性。此外,通过对成员类型使用继承技术的添加技巧,可以在运行时改变那些成员对象的类型和行为。因此可以在运行时改变组合而成的对象行为。(比如通过某set方法设置为另一个该成员的一个子对象,从而改变其行为) ->如果你的设计过于复杂,通过将现有类拆分为更小的部分而添加更多的对象,通常会有所帮助。19.部分源码:package com.book.chap7.reuse;
/** *//**
*
*详细讲述继承与初始化
*1.Beetle上运行java时,所发生的第一件事情就是访问Beetle的main,一个static方法,于是加载器开始启动并找出Beetle的加载代码,在名为Beetle.class中。在对它进行加载的过程
*中,编译器注意到它有一个基类,由关键字extends获得,于是它继续加载;不管你是否打算产生一个该基类的对象,这都要发生。如果该基类还有其自身的基类,那么第二个机会就会被
*加载,如此类推。接下来,根基类的static初始化,此类为Inspect,即会执行,然后是下一个导出类,以此类推。这种方式很重要,因为导出类的static初始化可能会依赖于基类成员能
*否被正确初始化
*2.到此为止,必要的类都已经加载完毕,对象就可以创建了。首先,对象中的所有基本类型都会被设置为默认值,对象引用被设置为null,这是通过将对象内存设为二进制零值而一举生成
*的。然后基类的构造器会被调用。本例中,是自动被调用的;基类的构造器和导出类的构造器一样,以相同的顺序来经历相同的过程。
*3.基类构造器完成之后,实例变量按此顺序被初始化。最后,构造器的其余部分被执行。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-26
*
*/
public class Beetle extends Inspect
{
private int k = printInit("Beetle.k initialized");
public Beetle()
{
System.out.println("j= " + j + " k =" + k);
}
private static int x2 = printInit("static Beetle.x2 initialized");
public static void main(Stringargs)
{
System.out.println("Bettle Constructor");
//可以将初始化的对象代码注释掉,不过static Inspect.x1 initialized和static Beetle.x2 initialized依然打印了出来
Beetle beetle = new Beetle();
}
}
class Inspect
{
private int i = 9;
protected int j;
public Inspect()
{
System.out.println("i = " + i + " j=" + j);
j = 23;
}
private static int x1 = printInit("static Inspect.x1 initialized");
static int printInit(String s)
{
System.out.println(s);
return 1;
}
}
package com.book.chap7.reuse;
/** *//**
*
*测试空白final的使用
*<p>不同的构造函数执行不同的初始化</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-19
*
*/
public class BlankFinal
{
private final int i = 0;//这里定义的时候就初始化了final
private final int j;//空白final,注:如果空白final一直未初始化的话,编译器会报错:The blank final field j may not have been initialized
private final Poppet poppet;//空白的final引用,编译器错误同上
public BlankFinal()
{
//构造函数中初始化black final fiend and reference
j = 1;
poppet = new Poppet(1);
}
public BlankFinal(int x)
{
//另一个构造函数初始化空白final不同的值
j = x;
poppet = new Poppet(x);
}
public static void main(Stringargs)
{
new BlankFinal();
new BlankFinal(24);
}
}
class Poppet
{
private int i;
public Poppet(int ii)
{
i = ii;
}
}
package com.book.chap7.reuse;
import static java.lang.System.out;
/** *//**
*
*CAD系统
*<p>本例测试复用过程中的正确清理1.自己的清理方法2.按照C++析构的顺序,同构造函数相反</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-17
*
*/
public class CADSystem extends Shape
{
//TODO 注意三个成员变量的声明顺序,析构的顺序即dispose方法的顺序和声明顺序相反
private Circle c;
private Triangle t;
private Line[] lines = new Line[3];
//注意构造顺序->1.首先必须调用super2.按照声明的成员顺序构造(C++做法),当然也可以不按照声明顺序3.子类构造相关
public CADSystem(int i )
{
super(i + 1);
c = new Circle(1);
t = new Triangle(1);
for(int j = 0;j < lines.length;j++)
{
lines[j] = new Line(j,j * j);
}
out.println("combined constructor");
}
public void dispose()
{
out.println("CAD System dispose");
//TODO cleanup的清理顺序和初始化的顺序相反
for(int i = lines.length - 1;i >= 0;i --)
{
lines[i].dispose();
}
t.dispose();
c.dispose();
//最后调用基类的dispose方法
super.dispose();
}
public static void main(String[] args)
{
CADSystem system = new CADSystem(3);
try
{
}
finally
{
system.dispose();
}
}
}
/** *//**
*
* 基类Shape
*
* @author landon
*
*/
class Shape
{
public Shape(int i)
{
out.println("Shape Constructor");
}
void dispose()
{
out.println("Shape Dispose");
}
}
/** *//**
*
* Circle,继承Shape
* <p>构造的时候,首先调用了基类的构造函数;dispose的时候,首先调用自己的方法,最后调用基类的dispose方法</p>
*
* @author landon
*
*/
class Circle extends Shape
{
public Circle(int i)
{
super(i);
out.println("Drawing Circle");
}
@Override
void dispose()
{
out.println("Erasing Circle");
super.dispose();
}
}
/** *//**
*
* Triangle,继承Shape
* <p>构造的时候,首先调用了基类的构造函数;dispose的时候,首先调用自己的方法,最后调用基类的dispose方法</p>
*
* @author landon
*
*/
class Triangle extends Shape
{
public Triangle(int i)
{
super(i);
out.println("Drawing Triangle");
}
@Override
void dispose()
{
out.println("Erasing Triangle");
super.dispose();
}
}
/** *//**
*
* Line,继承Shape
* <p>构造的时候,首先调用了基类的构造函数;dispose的时候,首先调用自己的方法,最后调用基类的dispose方法</p>
*
* @author Administrator
*
*/
class Line extends Shape
{
//线的开始和结束点
private int start;
private int end;
public Line(int start,int end)
{
super(start);
this.start = start;
this.end = end;
out.println("Drawing line: " + this.start + " ," + this.end);
}
@Override
void dispose()
{
out.println("Erasing line: " + this.start + " ," + this.end);
super.dispose();
}
}
package com.book.chap7.reuse;
/** *//**
*
*final参数用法
*<p>参数列表中以声明的方式将参数指明为final,无法在方法中更改参数应用所指向的对象</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-23
*
*/
public class FinalArguments
{
void with(final Gizmo g)
{
//The final local variable g cannot be assigned. It must be blank and not using a compound assignment,报错,g是final的
//g = new Gizmo();
}
void without(Gizmo g)
{
g = new Gizmo();//ok,g is not final
g.spin();
}
//The final local variable i cannot be assigned. It must be blank and not using a compound assignment,报错,i is final,不能改变,can't change
void f(final int i)
{
//i++;
}
int g(final int i)
{
return i + 1;//基本类型只能读取
}
}
class Gizmo
{
public void spin()
{
}
}
package com.book.chap7.reuse;
import java.util.Random;
/** *//**
*
*测试Final数据的用法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-18
*
*/
public class FinalData
{
private static Random rand = new Random(24);
private String id;
public FinalData(String id)
{
this.id = id;
}
//下面这两个定义属于编译期常量
private final int valueOne = 9;
private static final int VALUE_TWO = 99;
//典型的常量,public
public static final int VALUE_THREE = 39;
//不能成为编译器常量,因为数据是运行时随机获取
private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
private Value v1 = new Value(3);
//final 引用
private final Value v2 = new Value(33);
private static final Value VALUE_3 = new Value(44);
//final数组
private final int[] a = {1,2,3,4,5,6};
@Override
public String toString()
{
return id + ": " + " i4=" + i4 + ",INT_5=" + INT_5;
}
public static void main(Stringargs)
{
//因为是在当前类,所以fd1,fd2当然可以访问所有private变量;
//因为FinalData就是当前类,所以当然可以访问;如果FinalData定义在别处,则肯定无法访问或者在定义一个测试类,测试类的main中调用private,肯定是无法访问的。
FinalData fd1 = new FinalData("fd1");
//fd1.valueOne++;//不能改变值
fd1.v2.i++;//引用是final的,不过对象不是常量
fd1.v1 = new Value(9);// 可以,因为该引用不是final的
for(int i = 0;i < fd1.a.length;i++)
{
fd1.a[i]++;//ok,因为数组里面的对象不是常量
}
//he final field X cannot be assigned
//fd1.v2 = new Value(0);//final引用,不能改变引用
//fd1.VALUE_3 = new Value(0);//原因同上
//fd1.a = new int[3];//原因同上
//注意:static final装载时已初始化,而不是每次创建新对象时都初始化
System.out.println(fd1);
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData("fd2");
System.out.println(fd1);
System.out.println(fd2);
System.out.println(fd1);
System.out.println(fd2);
}
}
/** *//** 测试的一个引用对象 */
class Value
{
int i;
public Value(int i)
{
this.i = i;
}
}
package com.book.chap7.reuse;
import static java.lang.System.out;
/** *//**
*
*测试子类继承中的重载名字屏蔽问题
*<p>子类重载方法不会屏蔽其在基类中的任何版本,这和C++不同</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-17
*
*/
public class Hide
{
public static void main(Stringargs)
{
Bart bart = new Bart();
//在这里我们看到,Bart导出类没有屏蔽基类的任何doh版本
bart.doh('c');
bart.doh(2.0f);
bart.doh(new Milhouse());
}
}
/** *//**
*
* 基类,含有两个重载方法,doh
*
* @author landon
*
*/
class Homer
{
char doh(char c)
{
out.println("doh(char)");
return 'l';
}
float doh(float f)
{
out.println("doh(float)");
return 1.0f;
}
}
class Milhouse
{
}
/** *//**
*
* 一个导出类,继承自Home,并重载了基类的doh方法
*
* @author landon
*
*/
class Bart extends Homer
{
//Bart引入了一个新的重载方法,在C++中,如果派生类的函数与基类的函数同名(但是参数不同),则会屏蔽其同名的基类函数
void doh(Milhouse m)
{
out.println("doh(Milhouse)");
}
}
package com.book.chap7.reuse;
/** *//**
*
*测试protected关键字
*<p>尽量不要提供protected域,而只提供protected方法</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-18
*
*/
public class Orc extends Villain
{
private int orcNumber;
public Orc(String name,int number)
{
super(name);
this.orcNumber = number;
}
public void change(String name,int number)
{
//注:这里调用了基类的protected方法
//TODO 这里也可以调用super.setName()方法,因为setName为protected,该方法在子类可见
setName(name);
// super.setName(name);
orcNumber = number;
}
//这里调用了基类的toString方法
@Override
public String toString()
{
return "Orc " + orcNumber + ": " + super.toString();
}
public static void main(Stringargs)
{
Orc orc = new Orc("tracy", 20);
System.out.println(orc);
orc.change("landon", 5);
System.out.println(orc);
}
}
class Villain
{
private String name;
//protected方法
protected void setName(String nm)
{
name = nm;
}
public Villain(String name)
{
this.name = name;
}
@Override
public String toString()
{
return "I'm a villain and my name is " + name;
}
} package com.book.chap7.reuse;
/** *//**
*
*构造太空船的一种方式是使用继承
*<p>然而SpaceShip并非真正的SpaceShipControl,即便你可以告诉SpaceShip向前运行(forward)</p>
*<p>更准确的讲,SpaceShip包含SpaceShipControl,于此同时SpaceShipControl的所有方法在SpaceShip中都暴露了出来</p>
*
*{@link SpaceShipDelegation}
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-17
*
*/
public class SpaceShip extends SpaceShipControl
{
private String name;
public SpaceShip(String name)
{
this.name = name;
}
@Override
public String toString()
{
return name;
}
public static void main(Stringargs)
{
SpaceShip ship = new SpaceShip("tracy landon");
//调用了基类的forward方法
ship.forward(100);
}
}
package com.book.chap7.reuse;
/** *//**
*
*太空船控制模块
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-17
*
*/
public class SpaceShipControl
{
/** *//**
*
* 以某速度上
*
* @param velocity
*/
void up(int velocity)
{
}
/** *//**
*
* 以某速度下
*
* @param velocity
*/
void down(int velocity)
{
}
/** *//**
*
* 以某速度左
*
* @param velocity
*/
void left(int velocity)
{
}
/** *//**
*
* 以某速度右
*
* @param velocity
*/
void right(int velocity)
{
}
/** *//**
*
* 以某速度前
*
* @param velocity
*/
void forward(int velocity)
{
}
/** *//**
*
* 以某速度后
*
* @param velocity
*/
void back(int velocity)
{
}
/** *//**
* 发动机 加速
*/
void turboBoost()
{
}
}
package com.book.chap7.reuse;
/** *//**
*
*飞船代理
*<p>代理方式,介于继承和组合的一个中庸之道</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-17
*
*/
public class SpaceShipDelegation
{
private String name;
//SpaceShipControl作为该类的成员,飞船控制
private SpaceShipControl control = new SpaceShipControl();
public SpaceShipDelegation(String name)
{
this.name = name;
}
//Delegated method,所有的代理方法,该类中暴露了所有SpaceShipControl的方法
//右键Source->Generate Delegate Methods
public void up(int velocity)
{
control.up(velocity);
}
public void down(int velocity)
{
control.down(velocity);
}
public void left(int velocity)
{
control.left(velocity);
}
public void right(int velocity)
{
control.right(velocity);
}
public void forward(int velocity)
{
control.forward(velocity);
}
public void back(int velocity)
{
control.back(velocity);
}
public void turboBoost()
{
control.turboBoost();
}
public static void main(Stringargs)
{
SpaceShipDelegation ship = new SpaceShipDelegation("tracy mcgrady");
//通过调用代理的control的forward方法
ship.forward(100);
}
}
posted on 2013-01-08 17:40
landon 阅读(1394)
评论(0) 编辑 收藏 所属分类:
Program 、
Book