首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >编程思想 之「继承、组合、fianl」

编程思想 之「继承、组合、fianl」

作者头像
CG国斌
发布2019-05-26 14:42:10
3060
发布2019-05-26 14:42:10
举报
文章被收录于专栏:维C果糖维C果糖维C果糖

提起「复用类」三个字,相信我们脑海中浮现的都是「组合」和「继承」,实际上,在 Java 中复用类的方法也确实是这两种。

继承

Java 用super关键字表示超类(或称之为基类)的意思,意味着:当前类是从超类中继承而来的。当我们创建一个继承超类的导出类的对象的时候,该对象就包含了一个超类的子对象。这个子对象与我们用超类直接创建的对象是一样的,两者的区别在于,后者来自于外部,而超类的子对象被包装在导出类对象的内部。Java 会自动在导出类的构造器中插入对基类构造器的调用,例如,

package com.hit.chapter7;

/**
 * author:Charies Gavin
 * date:2017/12/30,16:22
 * https:github.com/guobinhit
 * description:测试导出类对象包含子类对象
 */
public class ClassA extends ClassB {
    public ClassA() {
        System.out.println("==== ClassA extends ClassB ==");
    }

    public static void main(String[] args) {
        new ClassA();
    }
}

class ClassB extends ClassC {
    public ClassB() {
        System.out.println("==== ClassB extends ClassC ==");
    }
}

class ClassC {
    public ClassC() {
        System.out.println("==== ClassC ==");
    }
}
extend
extend

通过上面的测试,我们会发现:类的构建过程是从超类向外“扩散”的

如果没有默认的超类构造器,或者想调用一个带参数的超类构造器,我们就必须使用关键字super显式地编写调用超类构造器的语句,并且配以适当的参数列表。此外,还要注意:调用超类构造器必须是我们在导出类构造器中做的第一件事

组合

我们有一个设计原则,那就是:多用组合,少用继承

相比于继承来说,组合更加灵活。组合通常用于想在新类中使用现有类的功能而非它的接口这种情形。举一个简单的例子,如果我们想创建一个Car,而 1 个Car包含 4 个Wheel、4 个Door和 6 个Window,这显然是has-a的关系而不是is-a的关系,何况 Java 也不支持多继承,这时使用组合就显得尤为合理.

final

一个既是static又是final的域只占据一段不能改变的存储空间。

对于基本类型,final使数值恒定不变;而对于对象的引用,final使引用恒定不变,然后对象自身却是可以被修改的。

在我们定义一个常量的时候,大都会使用如下格式:

public static final int CONSTANT = 521;

其中,定义为

  • public,表示它可以被用于包外;
  • static,强调它只有一个;
  • final,则说明它是一个常量。

Java 允许生产空白final,所谓空白final是指被声明为final但又未给定初值的域。不过我们必须在域的定义处或者每个构造器中用表达式对final进行赋值,以确保空白final在使用前必须被初始化。

Java 也允许在参数列表中以声明的的方式将参数指明为final,这意味着我们无法在方法中更改参数所指向的对象。例如,

package com.hit.chapter7;

/**
 * author:Charies Gavin
 * date:2017/12/30,17:34
 * https:github.com/guobinhit
 * description:测试方法中的 final 参数
 */
public class FinalParamter {
    /**
     * 无法修改 final 参数所指向的引用
     * @param apple
     */
//    public void eat(final Apple apple){
//        apple = new Apple();
//        apple.peel(apple);
//    }

    public void wash(Apple apple) {
        apple = new Apple();
        apple.peel(apple);
    }

    /**
     * 无法修改 final 参数所指向的引用
     * @param i
     */
//    public void printNum_1(final int i) {
//        System.out.println(i++);
//    }

    public void printNum_2(final int j) {
        System.out.println(j + 1);
    }

    public static void main(String[] args) {
        FinalParamter finalParamter = new FinalParamter();
        finalParamter.wash(null);
        finalParamter.printNum_2(5);
    }
}

class Apple {
    public void peel(Apple apple) {
        System.out.println("Apple apple, peel apple...");
    }
}

在 Java SE5 之前,使用final关键字修饰方法主要有两种原因,

  • 第 1 个原因:锁定方法,以防止任何继承类修改它的定义;
  • 第 2 个原因:提升运行效率。

但是随着 JDK 版本的迭代,我们已经不需要使用final方法来提升效率了,现在使用final方法的唯一理由就是:禁止子类覆盖父类中的方法

类中所有的private方法都隐式地指定为final的;final类中所有的方法也都隐式指定为final的,因此final类无法继承,其方法也无法覆盖。

一般来说,“类的代码在初次使用时才加载”,其含义通常是指:加载发生于创建类的第一个对象之时,但是当访问static域或者static方法时,也会发生加载。实际上,构造器也是static方法,尽管static关键字没有显式地写出来。因此,更准确的讲,类是在其任何static成员被访问时加载的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年12月30日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 继承
  • 组合
  • final
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档