第七章 复用类

第一种方法非常直观:只需在新的类中产生现有类的对象(组合)。

第二种方法更细致一些:它按照现有类的类型来创建新类(继承)。

7.1 组合语法

  只需将对象引用置于新类中即可。

class A{}
class B{
A a = new A();
}

  如果想初始化这些引用,可在下列位置进行:

  1. 在定义对象的地方。
  2. 在类的构造器中。
  3. 在真正使用这些对象之前,惰性初始化。
  4. 使用实例初始化。

7.2 继承语法

当创建一个类时,总是在继承。

  在继承过程中,需要先声明“新类与旧类相似”。在基类名称后紧随关键词extends,当这么做时,会自动得到基类中所有的域和方法。

  为了继承,一般将数据成员指定为private,将方法指定为public(protected成员也可以借助导出类访问)。

  Java使用super关键字表示超类,当前类就是从超类继承来的,如super.scrub()将调用基类(父类)版本的scrub()。

7.2.1 初始化基类

  当创建一个导出类对象,该对象包含了一个基类的子对象。这个字对象与你用基类直接创建的对象是一样的。

  Java会自动在导出类的构造器中插入对基类构造器的调用。

7.3 代理

  代理是继承和组合之家你的中庸之道。将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象所有方法(就像继承)。

class AControls{
void up(){}
void down(){}
}
class B{
AControls a = new AControls();
void up(int i){
a.up(i);
}
void down(int i){
a.down(i);
}
}

7.4 在组合和继承之间选择

  is-a(是一个)的关系用继承来表达。

  has-a(有一个)的关系用组合来表达。

7.5 protected关键字

  就类用户而言,这是private的,但对于任何继承于此类的导出类或其他任何位于同一包内的类来说,它却可以访问。

7.6 向上转型

  “为新的类提供方法”并不是继承最总要的,最重要的方面是用来表现新类和基类之间的关系。这种关系可以用“新类是现有类的一种类型”概括。

class A{
public void play(){}
static void tune(A a){
a.play();
}
}
class B extends A{
public static void main(String[] args){
B b = new B();
A.tune(b); // 向上转型
}

  在tune()中,程序代码可以对A(父类)和他所有的导出类(子类)起作用,这种将B(子)引用转换为A(父)引用的动作,称之为向上转型。

7.6.1 为什么称为向上转型

  由导出类转型为基类,在继承图上是向上移动的,一般称向上转型。由于向上转型是从一个较专用类型向较普通类型转换,所以总是很安全的。

7.6.2 再论组合与继承

  一个最清晰的判断办法就是问一问自己是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必要的,但如果不需要,则应当考虑是否继承。

7.7 final关键字

7.7.1 final数据

  1. 一个永不改变的编译时常量。
  2. 一个在运行时被初始化的值,而你不希望它被改变。

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

  当对对象引用而不是基本类型运用final时,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法把它改为指向另一个对象,然而,对象其自身却可以修改(指针不能变,对象内存域中的值可以变)。

  不能因为某数据是final就认为在编译时可知的,如果使用随机数初始化在编译时不可知。

空白final

  被声明为final但又未给初始值的域,提高了灵活性,必须在域的定义处或每个构造器中用表达式对final进行赋值。

final参数

  Java允许在参数列表中将参数声明为final,意味着方法中无法更改引用指向。可以读参数,无法修改参数,主要用来向匿名内部类传递数据

7.7.2 final方法

  1. 锁定方法,防止任何继承类修改它的含义,使方法形为不变,不会被覆盖。
  2. (早期)使用final方法效率高。

final和private关键字

  类中所有的private方法都是隐式地指定为final的。

  这会造成混淆,如果你覆盖一个private方法(隐含final),似乎是奏效的。“覆盖”只有在某方法是基类的接口的一部分时才会出现(能向上转型为基类并调用相同方法)。如果某方法为private,它就不是基类的接口的一部分。如果在导出类中以相同名称生成public、protected或包访问权限方法,此时没有覆盖该方法,仅是生成新方法。由于private无法触及而且有效隐藏,只看成它归属类的组织结构,其他情况不考虑。

7.7.3 final类

  当将某个类定义为final,表明不打算继承该类,且不允许别人这样做。该类设计永不变动,并且不希望它有子类。final类中的方法也是隐式final的,无法覆盖。

7.8 初始化及类的加载

  Java中的所有事物都是对象。每个类的编译文件都存在于它自己的独立文件中。该文件只有需要使用时才被加载。一般来说”类的代码在初次使用时才加载”。

  初次使用指:

  1. 创建类的第一个对象(创建对象调用构造器,构造器也是隐式static,准确的说,类是在任何static成员被访问时加载)。
  2. 访问static域或static方法。

7.8.1 继承与初始化

class A{
private int i = 9;
protected int j;
A(){
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 = printInit("static A.x1 initialized");
static int printInit(String s){
System.out.println(s);
return 47;
}
} class B extends A{
private int k = printInit("B.k initialized");
public B(){
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2 = printInit("static B.x2 initialized");
public static void main(String[] args){
System.out.println("B constructor");
B b = new B();
}
}

输出

static A.x1 initialized-------------父类静态成员初始化
static B.x2 initialized-------------子类静态成员初始化
B constructor-----------------------子类main(静态)打印语句
//此时声明B b = new B();
父类普通成员初始化i=9
i = 9, j = 0------------------------父类构造器打印语句
父类构造器中初始化j=39
B.k initialized---------------------子类普通成员初始化k=47
k = 47------------------------------子类构造器打印语句
j = 39 子类构造器打印语句

  初始化过程如下:

父类静态-子类静态-父类构造-父类变量-子类构造-子类变量

  1. 在B上运行Java时,发生的第一件事就是试图访问B.main()(一个static方法),于是加载器开始启动并找出B类的编译代码(在名为B.class的文件中)。

  2. 在对B.class加载过程中,编译器注意到B有一个基类A,于是它继续进行加载A。不管你是否打算产生一个该基类对象,这都要发生。

    2.1 如果该基类还有其自身的基类,那么第二个基类被加载,以此类推。

  3. 根基类(A类)中的static初始化被执行。

    3.1 然后是下一个导出类的static初始化,以此类推。

  4. 到此为止,必要的类都已加载完毕,对象可以被创建。

    4.1 首先,基类(A类)对象所有的基本类型都被设为默认值,对象引用设为null。

    4.2 基类(A类)构造器被调用。

    4.3 基类(A类)构造器和导出类(B类)构造器一样,以相同顺序执行。

    4.4 在基类构造器完成之后,实例变量按照其次续被初始化。

    4.5 最后构造器的其余部分被执行。

[Java编程思想] 第七章 复用类的更多相关文章

  1. Java编程思想第七章复用类

    7.1组合语法 在一个类中引入多个对象,以提高代码的复用性与功能. 7.2继承语法 使用继承子类可以获得,导出类可以获得基类的成员(变量与方法). 注:这里注意权限控制,若基类中的成员为默认权限,只有 ...

  2. Java编程思想——第17章 容器深入研究 读书笔记(三)

    七.队列 排队,先进先出. 除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: ad ...

  3. Java编程思想——第17章 容器深入研究(two)

    六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ...

  4. Java编程思想 第21章 并发

    这是在2013年的笔记整理.现在重新拿出来,放在网上,重新总结下. 两种基本的线程实现方式 以及中断 package thread; /** * * @author zjf * @create_tim ...

  5. java编程思想笔记(第一章)

    Alan Kay 第一个定义了面向对象的语言 1.万物皆对象 2.程序是对象的集合,他们彼此通过发送消息来调用对方. 3.每个对象都拥有由其他对象所构成的存储 4.每个对象都拥有其类型(TYpe) 5 ...

  6. 《Java编程思想》笔记 第七章 复用类

    1.组合 将其他类的对象引用置于新的类中. 3.继承 extends 从已知的一个类中派生出新的一个类,叫子类.子类实现了父类所有 非私有化 非静态 的属性和方法,并能根据自己的实际需求扩展出新的行为 ...

  7. 《java编程思想》P125-P140(第七章复用类部分)

    1.类的成员默认的是包访问权限.允许包内成员访问 2.super.scrub() 调用基类的scrub方法 3.继承并不是复制基类的接口.当创建了一个导出类(子类)对象时,该对象包含了一个基类的子对象 ...

  8. 初读"Thinking in Java"读书笔记之第七章 --- 复用类

    组合语法 将对象引用置于新类中,即形成类的组合. 引用初始化方法 在定义处初始化. 在类的构造器中初始化. 在使用这些对象之前,进行"惰性初始化". 使用实例初始化. 继承语法 J ...

  9. Java编程思想学习(七) 抽象类和接口

    1.抽象类和抽象方法 抽象方法:不完整的,仅有声明而没有方法体. abstract void f(); 抽象类:包含抽象方法的类.(若一个类包含一个或多个抽象方法,则该类必须限定为抽象的.) 1.用抽 ...

随机推荐

  1. Asp-Net-Core开发笔记:使用NPM和gulp管理前端静态文件

    前言 本文介绍的是AspNetCore的MVC项目,WebApi+独立前端这种前后端分离的项目就不需要多此一举了~默认前端小伙伴是懂得使用前端工具链的. 为啥要用MVC这种服务端渲染技术呢? 简单项目 ...

  2. 虚拟机搭建web服务器

    下载CentOS镜像 下载网址:阿里云镜像 选择版本(这里我使用的7) 选择isos/ 选择Minimal.iso,这个版本是最小镜像安装:没有图像界面 只有命令行 将CentOS安装到VM16中 注 ...

  3. Spring Boot Web项目整合jsp页面访问

    这个内容就是实操过程中各种访问不了jsp页面,各种尝试后的解决方案吧.可能不是最优的,但是目前能解决项目中的一些问题.之前觉得没有什么问题直接可以操作的,没想到在这部分还是耗时了. 开发工具idea2 ...

  4. const 和指针之间的姻缘

    const和指针到底有何姻缘呢? char const *p = NULL; //char const 和 const char 是一样的,p 是一个指向常整型的指针变量 ,指针变量的值不能改变 ch ...

  5. Wireshark教程之界面介绍

    实验目的 1.工具介绍 2.主要应用 实验原理 1.网络管理员用来解决网络问题 2.网络安全工程师用来检测安全隐患 3.开发人员用来测试执行情况 4.学习网络协议 实验内容 1.菜单栏选项介绍 2.快 ...

  6. 报表软件测评来啦!Smartbi电子表格使用感受

    最近因为工作需求,需要用到一些报表工具软件,看到Smartbi比较方便,可以直接在excel中进行配置,所以安装体验了一下. 下载 Smartbi有多个版本,我主要是在excel中使用,所以下载了一个 ...

  7. Dell服务器配置RAID1+RAID0磁盘阵列

    有台DELL R730的服务器,需要部署下公司的程序,这里记录下raid配置. 环境要求 两块硬盘做raid 1 一块硬盘做raid 0 服务器开机,开始配置raid 服务器开机,在出现下图提示时,同 ...

  8. Java:Path与Paths

    0.说明 用于读Path操作的接口(Path)与实现类(Paths) 1.模块:java.nio.file.Path.java.nio.file.Paths 2.方法 2.1.Paths 只有两个静态 ...

  9. python实用脚本-通过jenkins界面化导出数据

    1.jenkins 配置 2.jenkins 脚本 ansible-playbook /opt/test.yaml --extra-vars "loanno=${loanno}" ...

  10. JZ-061-序列化二叉树

    序列化二叉树 题目描述 请实现两个函数,分别用来序列化和反序列化二叉树. 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存. 序 ...