第七章 复用类(上)

来源:互联网 发布:淘宝shurese535假货 编辑:程序博客网 时间:2024/04/29 17:27

                     第七章  复用类

          这一章的知识我花了叫长时间去读,写了很多代码去验证书上所阐述的内容,并且也去测试自己的想法,所以总结的时候也很费时,暂时我只总结了这一章当中的一部分,明天继续加油。

        复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情。
        Java中所有的实物一样,问题解决都是围绕着类展开的。可以通过创建新类来复用代码,而不必再重头开始编写。可以使用别人已经开发并调试好的类。 在Java中有两种方法来达到代码复用的目的。
       第一种:这种方法非常直观,只需要在新的类中产生现有类的对象。由于新类是有现有类的对象所组成,所以这种方法称为组合。
       第二种:这种方法更细致一些,它按照现有类的类型来创建新类。无需改变现有类的形式,采用现有类的形式并在其中添加新代码。这种神奇的方式称为继承,并且编译器可以完成其中大部分工作。继承是面向对象程序设计的基石之一。

7.1  组合语法
     只需要将对象的引用置于新类中即可。
     编译器并不是简单地为每一个引用都创建默认对象,这一点是很有意义的,因为若真要那样做的话,就会在许多情况下增加不必要的负担,如果想初始化这些引用,可以在代码中的下列位置进行:
      1、在定义对象的地方。这意味着它们总是能够在构造器被调用之前被初始化。
      2、在类的构造器中。
      3、就在正要使用这些对象之前,这种方式称为惰性初始化。在生成对象不值得及不必每次都生成对象的情况下,这种方式可以减少额外的负担。
      4、使用实例初始化。
7.2  继承语法
      继承是所有OOP语言和Java语言不可缺少的组成部分。当创建一个类时,总是在继承,因此,除非已明确指出要从其他类中继承,否则就是在隐式地从Java的标准根类Object进行继承。
      在继承过程中,并不一定非得使用基类的方法。也可以在导出类中添加新方法,其添加方式与在类中添加任意方法一样,即对其加以定义即可。
7.2.1  初始化基类
      由于现在涉及基类和导出类这两个类,而不是只有一个类,所以要试着想象导出类所产生的结果对象,会有点困惑。从外部看,它就像是一个与基类具有相同接口的新类,或许还会有一些额外的方法和域。但继承并不只是复制基类的接口。当创建了一个导出类的对象时,该对象包含了一个基类的自对象。这个子对象与你用基类直接创建的对象是一样的。二者区别在于,后者来自于外部,而基类的子对象被包装在导出类对象内部。
      当然,对基类子对象的正确初始化也是至关重要的,而且也仅有一种方法来保证这一点:在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需的所有知识和能力。
     下面看懂这段代码就明白上述所讲的内容了:
     class Art{
     Art(){
          System.out.println("art contructor");
     }
}
class Drawing extends Art{
          Drawing(){
               System.out.println("drawing contructor");
          }
}
public class Cartoon extends Drawing{
     public Cartoon(){
          System.out.println("Cartoon contructor");
     }
     public static void main(String[] args) {
          Cartoon x = new Cartoon();

     }
}
运行结果:
art contructor
drawing contructor
Cartoon contructor


带参数的构造器
上列中各个类均含有默认的构造器,即这些构造器都不带参数。编译器可以轻松地调用它们是因为不必考虑要传递什么样的参数问题。但是,如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须用关键字super显式地编写基类构造器的语句,并且配以适当的参数列表:
   class Game{
     Game(int i){
          System.out.println("Game contructor");
     }
}
class BoardGame extends Game{
     BoardGame(int i) {
          super(11);
          System.out.println("BoardGame contructor");
     }
}
public class Chess extends BoardGame{
     Chess() {
          super(11);
          System.out.println("Chess contructor");
     }
     public static void main(String[] args) {
          new Chess();
     }
}
运行结果:
Game contructor
BoardGame contructor
Chess contructor

其实联想到我在android开发中,当你继承一个activity时,在方法中就会看到super这个关键字。

7.3  代理
      第三种关系称为代理,Java并没有提供对它的直接支持。这是继承与组合之间的中庸之道,因为我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的所有方法(就像继承)。例如,太空船需要一个控制模块:
     public class SpaceShipControls {
     void up(int velocity){}
     void down(int velocity){}
     void left(int velocity){}
     void right(int velocity){}
}
构造太空船的一种方式是使用继承:
     public class SpaceShip extends SpaceShipControls{
     private String name;
     public SpaceShip(String name){
          this.name=name;
     }
     public String toString(){
          return name;
     }
     public static void main(String[] args) {
          SpaceShip spaceShip = new SpaceShip("NSEA ");
          spaceShip.down(1);
     }
}
然而,SpaceShip并非真正的SpaceShipControls类型,即便你可以操作这些方法。更准确地讲,SpaceShip包含SpaceShipControls,与此同时,SpaceShipControls的所有方法在SpaceShip中都暴露了出来。这里如果使用组合也是一样会暴露。但是代理解决了此难题:
      public class SpaceShipDelegation {
     private String name;
     private SpaceShipControls controls=new SpaceShipControls();
     public SpaceShipDelegation(String name){
          this.name=name;
     }
     public void down(int velocity){
          controls.down(velocity);
     }
     public void up(int velocity){
          controls.up(velocity);
     }
     public void left(int velocity){
          controls.left(velocity);
     }
     public void right(int velocity){
          controls.right(velocity);
     }
     public static void main(String[] args) {
          SpaceShipDelegation delegation = new SpaceShipDelegation("NSEA");
          delegation.down(1);
     }

}

7.4  结合使用组合和继承
      同时使用组合和继承是很常见的事,例如:
       class Plate{
     Plate(int i){
          System.out.println("Plate constructor");
     }
}
class DinnerPlate extends Plate{
     DinnerPlate(int i) {
          super(i);
          System.out.println("DinnerPlate constructor");
     }
}
class Utensil{
     Utensil(int i){
          System.out.println("Utensil constructor");
     }
}
class Spoon extends Utensil{
     Spoon(int i) {
          super(i);
          System.out.println("Spoon constructor");
     }
}
class Fork extends Utensil{
     Fork(int i) {
          super(i);
          System.out.println("Fork constructor");
     }
}
class Custom{
     Custom(int i){
          System.out.println("Custom constructor");
     }
}
public class PlaceSetting extends Custom{
     private Spoon sp;
     private Fork frk;
     private DinnerPlate pl;
     PlaceSetting(int i) {
          super(i+1);
          sp=new Spoon(i+2);
          frk=new Fork(i+3);
          pl=new DinnerPlate(i+4);
          System.out.println("PlaceSetting constructor");
     }
     public static void main(String[] args) {
          new PlaceSetting(9);
     }

}
运行结果:
Custom constructor
Utensil constructor
Spoon constructor
Utensil constructor
Fork constructor
Plate constructor
DinnerPlate constructor
PlaceSetting constructor
 
       虽然编译强制你去初始化基类,并且要求你在构造器的起始处就要这么做,但是它并不监督你必须将成员对象也初始化,因此在这一点上自己必须时刻注意。
  

0 0
原创粉丝点击