Java编程思想——day 7(复用类)


Java编程思想——day 7

从现在开始,每天学习并记录。

2018/03/21


第七章 复用类

1、组合语法

将对象引用至于新类中,即为组合!
这里写图片描述
以下为四种方式的示例:

//: reusing/Bath.java
// Constructor initialization with composition.
import static net.mindview.util.Print.*;

class Soap {
  private String s;
  Soap() {
    print("Soap()");
    s = "Constructed";
  }
  public String toString() { return s; }
}   

public class Bath {
  private String // 1.Initializing at point of definition:
    s1 = "Happy",
    s2 = "Happy",
    s3, s4;
  private Soap castille;
  private int i;
  private float toy;
  public Bath() {//2.Initialization in the constructor
    print("Inside Bath()");
    s3 = "Joy";
    toy = 3.14f;
    castille = new Soap();
  } 
  // Instance initialization:
  { i = 47; }
  public String toString() {
    if(s4 == null) // Delayed initialization:
      s4 = "Joy";
    return
      "s1 = " + s1 + "\n" +
      "s2 = " + s2 + "\n" +
      "s3 = " + s3 + "\n" +
      "s4 = " + s4 + "\n" +
      "i = " + i + "\n" +
      "toy = " + toy + "\n" +
      "castille = " + castille;
  } 
  public static void main(String[] args) {
    Bath b = new Bath();
    print(b);
  }
} /* Output:
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
*///:~

2、继承语法

利用关键字extends完成继承!
这里写图片描述
举例:

import static net.mindview.util.Print.*;

class Cleanser {
  private String s = "Cleanser";
  public void append(String a) { s += a; }
  public void dilute() { append(" dilute()"); }
  public void apply() { append(" apply()"); }
  public void scrub() { append(" scrub()"); }
  public String toString() { return s; }
  public static void main(String[] args) {
    Cleanser x = new Cleanser();
    x.dilute(); x.apply(); x.scrub();
    print(x);
  }
}   

public class Detergent extends Cleanser {
  // Change a method:
  public void scrub() {
    append(" Detergent.scrub()");
    super.scrub(); // Call base-class version
  }
  // Add methods to the interface:
  public void foam() { append(" foam()"); }
  // Test the new class:
  public static void main(String[] args) {
    Detergent x = new Detergent();
    x.dilute();
    x.apply();
    x.scrub();
    x.foam();
    print(x);
    print("Testing base class:");
    Cleanser.main(args);
  } 
}

知识点:
这里写图片描述
这里写图片描述
super.scrub();表示调用基类的方法。
Cleanser.main(args);表示调用Cleanser类的main函数。
初始化:
基类在导出类构造器可以访问它之前,就已经完成了初始化。即构造器调用顺序为:先基类,后导出类(即子类、派生类、继承类)。
带参数的构造器
例子:

//: reusing/Chess.java
// Inheritance, constructors and arguments.
import static net.mindview.util.Print.*;

class Game {
  Game(int i) {
    print("Game constructor");
  }
}

class BoardGame extends Game {
  BoardGame(int i) {
    super(i);
    print("BoardGame constructor");
  }
}   

public class Chess extends BoardGame {
  Chess() {
    super(11);
    print("Chess constructor");
  }
  public static void main(String[] args) {
    Chess x = new Chess();
  }
} /* Output:
Game constructor
BoardGame constructor
Chess constructor
*///:~

这里写图片描述
在C++中可以利用成员初始化列表进行数据成员的赋初值。

3、代理

Java并没有提供对代理的直接支持,这是继承和组合的中庸之道。

4、结合使用组合和继承

  1. 确保正确清理: Java中没有C++中的析构函数,一般程序员不会去管对象的销毁,交给垃圾回收器。但有时类需要在其生命周期内进行必要的清理工作,此时需要显式的编写一个特殊的方法并要确保客户端程序员知晓他们必须要调用这一方法。就像在第12章所描述的那样,其首要任务就是,必须将这一清理动作置于finally子句之中,以预防异常的出现。
  2. 名称屏蔽: 如果Java的基类拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法名称并不会屏蔽其在基类中的任何版本(这一点与C++不同)。因此,无论是在该层或者它的基类对方法进行定义,重载机制都可以正常工作:

Java SE5新增加了@Override注解,它并不是关键字,但是可以把它当作关键字使用。当你想要覆写某个方法时,可以选择添加这个注解,在你不留心重载而并非覆写了该方法时,编译器就会生成一条错误消息:

method does not override a method from its superclass.

知识点: 方法重载 是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。 Java的方法重载,就是在类中可以创建多个方法,它们可以有相同的名字,但必须具有不同的参数,即或者是参数的个数不同,或者是参数的类型不同。调用方法时通过传递给它们的不同个数和类型的参数来决定具体使用哪个方法。
在Java和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用 方法的重写方法重写又称方法覆盖

5、组合和继承之间的选择

  1. 组合和继承都允许在新的类中放置子对象,组合是显式地这样做,而继承则是隐式地做。
  2. 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。即,在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌人对象的接口。为取得此效果,需要在新类中嵌入一个现有类的private对象。
    有时,允许类的用户直接访问新类中的组合成分是极具意义的;也就是说,将成员对象声明为public。如果成员对象自身都隐藏了具体实现,那么这种做法是安全的。当用户能够了解到你正在组装一组部件时,会使得端口更加易于理解。
  3. 在继承的时候,使用某个现有类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。略微思考一下就会发现,用一个“交通工具”对象来构成一部“车子”是毫无意义的,因为“车子”并不包含“交通工具”,它仅是一种交通工具(“is-a” 关系)。“is-a” (是一个)的关系是用继承来表达的,而“has-a” (有一个)的关系则是用组合来表达的。

6、protected关键字

  1. protected关键字提供了包内访问权限,并且也支持继承于此类的导出类。
  2. 最好的方式还是将域保持为private;你应当一直保留“更改底层实现”的权利。然后通过protected方法来控制类的继承者的访问权限。

7、向上转型

  1. 向上转型是安全的。

8、final关键字

final通常是指这是无法改变的,不想做出改变的原因是出于“设计或效率”
final用到的三种情况:数据、方法和类。

final数据
数据恒定不变的情况:
1. 一个永不改变的编译时常量
2. 一个在运行时被初始化的值,而你不希望它被改变。
3. 一个既是static又是final的域,只占据一段不能改变的存储空间。
final方法
final方法存在原因:
1. 把方法锁定,防止任何继承类修改它的含义。
2. 确保在继承中使方法行为保持不变,并且不会被覆盖。
类中所有的private方法都隐式地指定为是final的。
final类
1. final类不可以被继承。

猜你喜欢

转载自blog.csdn.net/yangxingpa/article/details/79647429