复用类

来源:互联网 发布:淘宝lv女包 编辑:程序博客网 时间:2024/05/17 22:21

一、复用类

  1. 组合语法:将对象引用置于新类中;
  2. 继承语法:Java会自动在导出类的构造器中插入对基类构造器的调用;
  3. 代理:代理是继承与组合之间的中庸之道,因为我们将一个成员变量对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的所有方法(就像继承)。代理解决了这种问题,可以向新类只暴露我们想让他使用的方法,不想让它使用的方法就不会被暴露;

二、在组合与集成之间选择

继承和组合都能从现有类型生成新类型。
组合一般是将现有类型作为新类型底层实现的一部分来加以复用的,而继承复用的是接口。

  1. 组合和继承都允许在新类中放置子对象,组合是显示地这样做,而继承则是隐式地做。
  2. 在新类中嵌入对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。为取得这个效果,需要在新类中嵌入一个现有类的private对象;
  3. 但有时候,允许类的用户直接访问新类中的组合成分是极具意义的,也就是说,将成员对象声明成public。如果成员对象自身都隐藏了具体实现,那么这种做法是安全的。当用户能够了解到你正在组装一组部件时,会使得端口更加易于理解。Car对象就是一个很好的例子:
class Engine{    public void start(){}    public void rev(){}    public void stop(){}}class Wheel{    public void inflate(int psi){}}class Window{    public void rollup(){}    public void rolldown(){}}class Door{    public Window window = new Window();    public void open(){}    public void close(){}}public class Car {    public Engine engine = new Engine();    public Wheel[] wheel = new Wheel[4];    public Door        left  = new Door(),        right = new Door();    public Car(){        for(int i=0;i<4;i++){            wheel[i] = new Wheel();        }    }    public static void main(String[] args) {        Car car = new Car();        car.left.window.rolldown();        car.wheel[0].inflate(72);    }}

所以使成员成为public将有助于客户端程序员了解怎样去使用类,而且也降低了类开发者所面临的代码复杂度。但务必记住这仅仅是一个特例,一般情况下应该使域成为private。

  • 在继承的时候,使用某个现有类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。
  • “is-a”(是一个)的关系是用继承来表达的,而“has-a”(有一个)的关系则是用组合来表达的。
  • 在面向对象编程中,我们通常将数据和方法包装进一个类中,并使用该类的对象。也可以运用组合技术使用现有类来开发新的类,而继承是不太常用的,要慎用这一技术。到底该用组合还是继承,一个最清晰的判断就是问一问自己是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必要的;

三、final关键字

1. final数据

  • 基本数据类型:
    向编译器告知一块数据是恒定不变的,比如:
    1、一个永不改变的编译时常量;
    2、一个在运行时被初始化的值,而你不希望它被改变;
    对于编译期常量,编译器可以将该常量带入任何可能用到它的计算式中,也就是说,可以在编译时执行计算式,这减轻了运行时负担。在对这个常量进行定义的时候,必须对其进行赋值。
  • 复合类:
    一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的。
  • 带有恒定初始值(即编译期常量)的final static基本类型全用大写字母命名,并且字与字之间用下划线隔开。
  • 空白final:
    Java允许生成“空白final”,指被声明为final但又未给定初始值的域。无论什么情况,编译器都确保空白final在使用前必须被初始化。但是,空白final在关键字final的使用上提供了更大的灵活性,为此,一个类中的final域就可以根据对象而有所不同,却又保持其恒定不变的特性。
class Poppet{    private int i;    Poppet(int ii){i = ii;}}public class BlankFinal{    private final int i = 0;    private final int j;//空白final    private final Poppet p;//空白final    public BlankFinal(){  //在构造器里必须初始化        j = 1;        p = new Poppet(1);    }    public BlankFinal(int x){        j = x;        p = new Poppet(x);    }    public static void main(String[] args) {        new BlankFinal();        new BlankFinal(23);    }}

如果没有在域的定义处初始化,就必须在每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在。

  • final参数
    Java允许在参数列表中以声明的方式将参数定义为final。这意味着你无法在方法中更改参数引用所指向的对象。这一特性主要用来向匿名内部类传递数据,后期会学到。

2.final方法

 为了防止任何继承类修改它的含义,想要切薄在继承中使方法行为保持不变,并且不会被覆盖;  类中所有private方法都隐式地指定为final的,由于无法取用private方法,所以也就无法覆盖它;而当我们在子类中重新定义一个private方法时,发现没有报错,似乎它还是可以被覆盖的,其实它仅是一个“具有相同名称”的新方法。

3.final类
final类禁止继承,所以final类中的所有方法都隐式指定为final的;

四、初始化及类的加载

类的代码在初次使用才会被加载。这通常是指加载发生于创建第一个对象之时,但是当访问static域和static方法时,也会发生加载。(构造器也是static方法,只是没有被显式的写出来。而确切的说,类是在任何static成员被访问时加载的。)

原创粉丝点击