java编程思想第四版第七章总结
1. 实现类的复用通常有两种方式
- 组合:在新的类中产生现有类的对象
- 继承:按照现有类的类型来创造新类
2. 一个特殊的方法toString()
- 在非基本类型的对象中, 都有toString()方法
- 当编译器需要一个String而你只有一个对象时, toString()方法会被自动调用
3. 父类方法的定义要求
- 所有的方法都是public的.
- 原因: 如果没有修饰符,则是包访问权限, 那么包以外的其他类继承了这个类, 依然不能访问这个父类的方法. 所以, 定义父类的公用方法需要时public的.
- 为了继承一般的规则是: 成员变量是private的, 方法是public的.
4. 基类初始化
- java会在子类中自动调用父类的构造器
- 父类如果没有默认构造器, 子类需要用super显示的调用父类的构造器. 而且调用父类构造器,必须是子类构造器要做的第一件事
- 基类的默认构造器, 也要显示的调用父类的有参构造器
5. 复用的第三种方式: 代理
- 代理: java并不直接支持他, 它是继承和组合之间的一种中庸之道.
- 无论我们使用的时组合, 还是继承. 都会暴露所有对象的成员方法
- 组合:在类中new一个对象, 然后该对象的所有成员方法在这个类中就都可以被使用。
- 继承:继承了父类, 那么父类的方法对这个子类来说, 更是完全可见的。
- 这两种方法都会完全暴掠被使用的那个类的成员方法, 而有的时候, 我们不希望这样, 不想父类或者被调用类的成员方法被暴露在外, 就可以采用代理的方式, 如下例:太空船需要一个控制模块
package net.mindview.reusing; public class SpaceShipControls {
//velocity 速度
void up(int velocity){}
void down(int velocity){}
void left(int velocity){}
void right(int velocity){}
void forward(int velocity){}
void back(int velocity){}
void turboBoost(int velocity){} //发动 }构造一个太空船, 可以使用组合或者继承。 我们这里使用继承的方式构造。
package net.mindview.reusing; public class SpaceShip extends SpaceShipControls {
private String name;
public SpaceShip(String name) {
this.name = name;
} @Override
public String toString() {
return name;
} public static void main(String[] args) {
SpaceShip protector = new SpaceShip("太空号");
protector.up();
} }然而, SpaceShip并非一个真正的SpaceShipControls类型。太空船是太空船, 并不是太空控制器, 只是使用了太空控制器而已。更准确的说:SpaceShip包含SpaceShipControls。而且, 一旦继承, SpaceShipControls的所有方法都在SpaceShip中暴露了。这时我们可以使用代理方式来解决这个问题:
package net.mindview.reusing;
/**
* 太空船代理
*/
public class SpaceShipDelegation {
String name;
public SpaceShipControls controls = new SpaceShipControls();
public SpaceShipDelegation(String name){
this.name = name;
} public void up(int velocity){
controls.up(velocity);
}
void down(int velocity){
controls.down(velocity);
}
void left(int velocity){
controls.left(velocity);
}
void right(int velocity){
controls.right(velocity);
}
void forward(int velocity){
controls.forward(velocity);
}
void back(int velocity){
controls.back(velocity);
}
void turboBoost(int velocity){//发动
controls.turboBoost(velocity);
} public static void main(String[] args) {
SpaceShipDelegation protector = new SpaceShipDelegation("太空号2");
protector.up();
}
}这就是使用了代理。 主要关注上面的方法是如何传递给底层的controls对象的。 其接口与使用继承得到的接口一样了。 然而,我们使用代理时却得到了更多的控制力。
6. 如何选择组合和继承
- 组合通常是想在新类中使用现有类的功能而非他的接口。就是说,在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口。而非锁嵌入对象的接口。为取得这个效果, 应该将现有类定义为private的。看下面的这个例子:
package net.mindview.reusing; 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[] wheels = new Wheel[];
public Door left = new Door(),right = new Door();
public Car(){
for(int i=;i<; i++){
wheels[i] = new Wheel();
}
}
public static void main(String[] args) {
Car car = new Car();
car.left.window.rollup();
car.wheels[].inflate();
}
}这里面, 显示的car的组成部分, 所以使用的是组合的方式。 而如果有一个“交通工具”和car是什么关系呢? 显然他们车不是交通工具组成的。car确实一类交通工具, 所以,交通工具和car应该是继承的关系。
- 向上转型
package net.mindview.reusing;
/**
* 乐器
*/
class Instrument {
public void play(){} //用乐器弹奏曲调
static void tune(Instrument i){
i.play();
}
} //乐器的一种
public class Wind extends Instrument{ public static void main(String[] args) {
Wind wind = new Wind();
//使用wind弹奏曲调
Instrument.tune(wind);
}
}
- 上面的Instrument类中, 接收的Instrument的引用,在使用的时候, 我们可以将继承了Instrument的乐器传给tune方法。这称之为向上转型。
- 到底什么时候使用组合, 什么时候使用继承呢?
- 一个最清晰的判断就是, 问问自己,是否需要从新类向基类向上转型。如果需要转型, 那么就必须使用继承,否则就要好好想想了, 是否有使用集成的必要性。
7.final关键字
- final关键字的含义通常是“这是无法改变的
- 作用于成员变量, 表示该变量编译时不可变。
- 作用于成员变量, 和public static一起使用, 表示全局常量
- 成员变量是对象类型时使用final表示, 对象的引用不可改变。
- 空白final
- 所谓“空白final“指的是, 在定义final变量的时候不给他赋初始值, 而是在构造函数中为其赋值。这样就提供了更大的灵活性。使用方法如下所示:
package net.mindview.reusing; class Poppet {
private int i;
Poppet(int i){
this.i = i;
}
} public class BlankFinal {
//定义的时候赋初始值
private final int i = ;
//空白final
private final int j;
//空白final引用
private final Poppet p; public BlankFinal(){
j = ;
p = new Poppet();
} public BlankFinal(int x){
j = x;
p = new Poppet(x);
} public static void main(String[] args) {
new BlankFinal();
new BlankFinal();
}
}
- 所谓“空白final“指的是, 在定义final变量的时候不给他赋初始值, 而是在构造函数中为其赋值。这样就提供了更大的灵活性。使用方法如下所示:
- 在参数列表中以声明的方式将参数指明为final
- 如果final作用的参数是对象,则表明在方法中无法更改参数引用所指向的对象。
- 如果final作用的是基本类型的参数, 则表示不可以改变传递过来的参数值。
package net.mindview.reusing; class Gizmo{
public void spin() {}
} //final作用于方法参数
public class FinalArguments {
//final作用于对象类型的方法参数
void with(final Gizmo g) {
//在这里不可以对传递过来个g重新指向新的引用
//g = new Gizmo();
} void without(Gizmo g){
g = new Gizmo();
g.spin();
} //final作用于基本类型的方法参数
void f(final int i) {
//在这里不可以对i重新赋值
//i++;
} int g(final int i) {
return i+;
} public static void main(String[] args) {
FinalArguments bf = new FinalArguments();
bf.with(null);
bf.without(null);
} }
- final方法
- 方法被定义final,则不可以被继承类修改。也就是确保方法的行为保持不变,不可被覆盖。
- final 类
- 当某各类被定义为final时,不可被继承
忠告:再设计类的时候, 将方法定义为final的,应该说是明智的。你可能会觉得,没人想要覆盖你的方法,但预见类是如何被复用是很困难的, 特别是对于一个通用类而言,更是如此。如果你将方法定义为final的, 可以防止其他程序员在项目中通过继承来复用你的类。
java编程思想第四版第七章总结的更多相关文章
- Java编程思想第四版*第七章*个人练习
欢迎加群:239063848 成团的笔记:该组仅用于技术共享和交流,问题和答案公布 潘基聊天.禁止广告.禁止招聘-- 练习1:(2)创建一个简单的类.第二个类中,将一个引用定义为第一个类的对象.运用惰 ...
- java编程思想第四版第七章习题
(略) (略) (略) (略) 创建两个带有默认构造器(空参数列表)的类A和类B.从A中继承产生一个名为C的新,并在C内创建一个B类的成员.不要给C编写构造器.创建一个C类的对象并观察其结果. pac ...
- java编程思想第四版第十三章字符串 习题
fas 第二题 package net.mindview.strings; import java.util.ArrayList; import java.util.List; /** * 无限循环 ...
- java编程思想第四版第十一章习题
第一题 package net.mindview.holding.test1; import java.util.ArrayList; import java.util.List; /** * 沙鼠 ...
- java编程思想第四版第六章习题
(略) (略) 创建两个包:debug和debugoff,他们都包含一个相同的类,该类有一个debug()方法,第一个版本显示发送给控制台的String参数,而第二版本什么也不做,使用静态import ...
- java编程思想第四版第六章总结
1. 代码重构 为什么f要代码重构 第一次代码不一定是完美的, 总会发现更优雅的写法. 代码重构需要考虑的问题 类库的修改不会破坏客户端程序员的代码. 源程序方便扩展和优化 2. 包 创建一个独一无二 ...
- java编程思想第四版第五章习题
创建一个类, 它包含一个未初始化的String引用.验证该引用被Java初始化成了null package net.mindview.initialization; public class Test ...
- java编程思想 第四版 第六章 个人练习
欢迎加群:239063848 进群须知:本群仅用于技术分享与交流.问题公布与解答 禁止闲聊.非诚勿扰 练习1:(1)在某个包中创建一个类,在这个类所处的包的外部创建该类的一个实例. import mi ...
- java编程思想第四版第十三章字符串 总结
1. String和StringBulider的使用 通过书中介绍, 我们得知如下结论: 当使用+连接符将字符串进行拼接的时候, 编译器会进行自动优化为使用StringBuilder连接字符串. 当在 ...
随机推荐
- mvc请求管道(一)
一.前言 在平常做后台开发的时候,经常会说到请求管道,很多开发者都知道这个,也能说几句,可能没法详细的去介绍,今天就来详细的说一下这个. 二.到达IIS之前 请看下面这个流程图.从用户打开浏览器到请求 ...
- PHP key_exists
此函数同array_key_exsits(). 1.函数的作用:判断一个数组是否含有某个键值 2.函数的参数: @param string $key @param array $haystack 3 ...
- MFC日期显示
一.使用MFC的CTime类来得到时间: CTime必须调用赋值函数,使用其静态函数来初始化 例如: CTime time=CTime::GetCurrentTime(): 这样就可以直接调用time ...
- HDU 6607 Time To Get Up(状态压缩+枚举)
题目网址: http://acm.hdu.edu.cn/showproblem.php?pid=6077 思路: 先预处理一下,将每个数字块的“X”看作1,“.”看作0,进行状态压缩转换成二进制数,用 ...
- vue-cli3 关闭一直运行的 /sockjs-node/info?t= ...
首先 sockjs-node 是一个JavaScript库,提供跨浏览器JavaScript的API,创建了一个低延迟.全双工的浏览器和web服务器之间通信通道. 本地项目运行就会自动去访问:http ...
- 基于 HTML5 + WebGL 的 3D 可视化挖掘机
前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...
- JVM(4) 类文件结构
一.实现“平台无关性” 字节码(ByteCode)存储格式和虚拟机是实现语言无关性的基础.Java虚拟机不和包括Java在内的任何语言绑定,它只与“Clas”文件这种特定的二进制文件格式所关联,Cla ...
- Redis(一)Redis基础
一.Redis是什么 Redis是一种基于键值对(key-value)的NoSQL数据库,与很多键值对数据库不同的是,Redis中的值可以是由string(字符串).hash(哈希).list(列表) ...
- 数据结构(四十一)多路查找树(B树)
一.多路查找树的背景 前面所讨论的查找算法都是在内存中进行的,它们适用于较小的文件,而对于较大的.存放在外存储器上的文件就不合适了,对于此类大规模的文件,即使是采用了平衡二叉树,在查找效率上仍然较低. ...
- 随机数产生器:Random.Next
Random类是一个产生伪随机数字的类,它的构造函数有两种,一个是直接New Random(),另外一个是New Random(Int32),前者是根据触发那刻的系统时间做为种子,来产生一个随机数字, ...