《java编程思想》第七章 复用类
组合:在新的类中产生现有类的对象。只是复用了现有程序代码的功能,而非形式。
继承:按照现有类的类型来创建新类,无需改变现有类的形式。采用现有类(基类)的形式,并在其中添加新代码。
都是利用现有类型生成新类型。
7.1组合语法
组合就是将对象引用置于新类中
//: reusing/SprinklerSystem.java
// Composition for code reuse.class WaterSource {private String s;WaterSource() {System.out.println("WaterSource()");s = "Constructed";}public String toString() { return s; }
} public class SprinklerSystem {private String valve1, valve2, valve3, valve4;private WaterSource source = new WaterSource();private int i;private float f;public String toString() {return"valve1 = " + valve1 + " " +"valve2 = " + valve2 + " " +"valve3 = " + valve3 + " " +"valve4 = " + valve4 + "\n" +"i = " + i + " " + "f = " + f + " " +"source = " + source;} public static void main(String[] args) {SprinklerSystem sprinklers = new SprinklerSystem();System.out.println(sprinklers);}
} /* Output:
WaterSource()
valve1 = null valve2 = null valve3 = null valve4 = null
i = 0 f = 0.0 source = Constructed
*///:~
对象引用被初始化为null,但试图为他们调用任何方法都会报错。
初始化引用的地方:
定义对象的地方,在构造器被调用之前被初始化。
在类的构造器中。
在正要使用这些对象之前,惰性初始化,不是每次都要生成对象的情况下。
使用实例初始化
//: 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 // Initializing at point of definition:s1 = "Happy",s2 = "Happy",s3, s4;private Soap castille;private int i;private float toy;public Bath() {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
*///:~
7.2继承语法
所有的类都是继承自标准根类Objects。继承会自动得到基类中所有的域和方法。
//: reusing/Detergent.java
// Inheritance syntax & properties.
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);}
} /* Output:
Cleanser dilute() apply() Detergent.scrub() scrub() foam()
Testing base class:
Cleanser dilute() apply() scrub()
*///:~
为了继承,一般的规则是将所有的数据成员都指定为private,将所有的方法指定为public。
super关键字表示超类,super.方法名,调用超类方法。
继承可以不使用超类的方法,添加新的方法。
继承并不只是复制基类的接口,当创建一个导出类的对象时,该对象包含了一个基类的子对象,这个子对象与用基类之间创建的是一样的,基类的子对象被包装在导出类对象的内部。
基类子对象初始化,在构造器中调用基类构造器初始化。Java自动在道出类的构造器中插入对基类构造器的调用:
//: reusing/Cartoon.java
// Constructor calls during inheritance.
import static net.mindview.util.Print.*;class Art {Art() { print("Art constructor"); }
}class Drawing extends Art {Drawing() { print("Drawing constructor"); }
}public class Cartoon extends Drawing {public Cartoon() { print("Cartoon constructor"); }public static void main(String[] args) {Cartoon x = new Cartoon();}
} /* Output:
Art constructor
Drawing constructor
Cartoon constructor
*///:~
基类在道出类构造器可以访问它之前,就已经完成了初始化。
带参数的构造器:
//: 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
*///:~
调用基类构造器必须是导出类构造器中要做的第一件事。
7.3代理
//: reusing/SpaceShipControls.javapublic class SpaceShipControls {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() {}
} ///:~//: reusing/SpaceShip.javapublic class SpaceShip extends SpaceShipControls {private String name;public SpaceShip(String name) { this.name = name; }public String toString() { return name; }public static void main(String[] args) {SpaceShip protector = new SpaceShip("NSEA Protector");protector.forward(100);}
} ///:~//: reusing/SpaceShipDelegation.javapublic class SpaceShipDelegation {private String name;private SpaceShipControls controls =new SpaceShipControls();public SpaceShipDelegation(String name) {this.name = name;}// Delegated methods:public void back(int velocity) {controls.back(velocity);}public void down(int velocity) {controls.down(velocity);}public void forward(int velocity) {controls.forward(velocity);}public void left(int velocity) {controls.left(velocity);}public void right(int velocity) {controls.right(velocity);}public void turboBoost() {controls.turboBoost();}public void up(int velocity) {controls.up(velocity);}public static void main(String[] args) {SpaceShipDelegation protector =new SpaceShipDelegation("NSEA Protector");protector.forward(100);}
} ///:~
7.4结合使用组合和继承
//: reusing/PlaceSetting.java
// Combining composition & inheritance.
import static net.mindview.util.Print.*;class Plate {Plate(int i) {print("Plate constructor");}
}class DinnerPlate extends Plate {DinnerPlate(int i) {super(i);print("DinnerPlate constructor");}
} class Utensil {Utensil(int i) {print("Utensil constructor");}
}class Spoon extends Utensil {Spoon(int i) {super(i);print("Spoon constructor");}
}class Fork extends Utensil {Fork(int i) {super(i);print("Fork constructor");}
} class Knife extends Utensil {Knife(int i) {super(i);print("Knife constructor");}
}// A cultural way of doing something:
class Custom {Custom(int i) {print("Custom constructor");}
} public class PlaceSetting extends Custom {private Spoon sp;private Fork frk;private Knife kn;private DinnerPlate pl;public PlaceSetting(int i) {super(i + 1);sp = new Spoon(i + 2);frk = new Fork(i + 3);kn = new Knife(i + 4);pl = new DinnerPlate(i + 5);print("PlaceSetting constructor");}public static void main(String[] args) {PlaceSetting x = new PlaceSetting(9);}
} /* Output:
Custom constructor
Utensil constructor
Spoon constructor
Utensil constructor
Fork constructor
Utensil constructor
Knife constructor
Plate constructor
DinnerPlate constructor
PlaceSetting constructor
*///:~
如果Java的基类拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法名称并不会屏蔽在基类中的任何版本。
//: reusing/Hide.java
// Overloading a base-class method name in a derived
// class does not hide the base-class versions.
import static net.mindview.util.Print.*;class Homer {char doh(char c) {print("doh(char)");return 'd';}float doh(float f) {print("doh(float)");return 1.0f;}
}class Milhouse {}class Bart extends Homer {void doh(Milhouse m) {print("doh(Milhouse)");}
}public class Hide {public static void main(String[] args) {Bart b = new Bart();b.doh(1);b.doh('x');b.doh(1.0f);b.doh(new Milhouse());}
} /* Output:
doh(float)
doh(char)
doh(float)
doh(Milhouse)
*///:~
@Override注解,在覆写某个方法的时候使用,可以添加这个注解,在重新的时候而非覆写的时候会报错。防止错误重载。
7.5在组合与继承之间选择
组合是在新类中使用现有类的功能而不是接口。在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。需要在新类中嵌入一个现有类的private。
7.6protected关键字
继承的类可用,而对于其他类来说是private。同时也是包访问权限。
//: reusing/Orc.java
// The protected keyword.
import static net.mindview.util.Print.*;class Villain {private String name;protected void set(String nm) { name = nm; }public Villain(String name) { this.name = name; }public String toString() {return "I'm a Villain and my name is " + name;}
} public class Orc extends Villain {private int orcNumber;public Orc(String name, int orcNumber) {super(name);this.orcNumber = orcNumber;}public void change(String name, int orcNumber) {set(name); // Available because it's protectedthis.orcNumber = orcNumber;}public String toString() {return "Orc " + orcNumber + ": " + super.toString();} public static void main(String[] args) {Orc orc = new Orc("Limburger", 12);print(orc);orc.change("Bob", 19);print(orc);}
} /* Output:
Orc 12: I'm a Villain and my name is Limburger
Orc 19: I'm a Villain and my name is Bob
*///:~
7.7向上转型
继承最重要的作用是用来表示新类和基类之间的关系。新类是现有类的一种类型。
向上转型:
//: reusing/Wind.java
// Inheritance & upcasting.class Instrument {public void play() {}static void tune(Instrument i) {// ...i.play();}
}// Wind objects are instruments
// because they have the same interface:
public class Wind extends Instrument {public static void main(String[] args) {Wind flute = new Wind();Instrument.tune(flute); // Upcasting}
} ///:~
到底使用组合还是继承?
是否需要从新类向基类进行向上转型。需要就用继承,不需要就需要慎重考录了。
7.8final关键字
final可以用在数据、方法、类之前。
数据使用final:
一个永不改变的编译时常量(即是static又是final)。
在运行时被初始化的值,不希望改变的存储空间。
使用final引用对象,引用恒定不变。
//: reusing/FinalData.java
// The effect of final on fields.
import java.util.*;
import static net.mindview.util.Print.*;class Value {int i; // Package accesspublic Value(int i) { this.i = i; }
}public class FinalData {private static Random rand = new Random(47);private String id;public FinalData(String id) { this.id = id; }// Can be compile-time constants:private final int valueOne = 9;private static final int VALUE_TWO = 99;// Typical public constant:public static final int VALUE_THREE = 39;// Cannot be compile-time constants:private final int i4 = rand.nextInt(20);static final int INT_5 = rand.nextInt(20);private Value v1 = new Value(11);private final Value v2 = new Value(22);private static final Value VAL_3 = new Value(33);// Arrays:private final int[] a = { 1, 2, 3, 4, 5, 6 };public String toString() {return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;}public static void main(String[] args) {FinalData fd1 = new FinalData("fd1");//! fd1.valueOne++; // Error: can't change valuefd1.v2.i++; // Object isn't constant!fd1.v1 = new Value(9); // OK -- not finalfor(int i = 0; i < fd1.a.length; i++)fd1.a[i]++; // Object isn't constant!//! fd1.v2 = new Value(0); // Error: Can't//! fd1.VAL_3 = new Value(1); // change reference//! fd1.a = new int[3];print(fd1);print("Creating new FinalData");FinalData fd2 = new FinalData("fd2");print(fd1);print(fd2);}
} /* Output:
fd1: i4 = 15, INT_5 = 18
Creating new FinalData
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
*///:~
static强调只有一份,final强调是一个常量。
final参数主要用在匿名内部类传递数据。
final方法,将方法锁定,防止任何继承类修改它的含义。
类中所有的private方法都隐式的显示为final,因为无法访问,所以无法修改。
7.9初始化及类的加载
类的代码在初次使用时才加载,通常加载发生在创建类的第一个对象之时。但当访问static域或者static方法时,也会发生加载。
//: reusing/Beetle.java
// The full process of initialization.
import static net.mindview.util.Print.*;class Insect {private int i = 9;protected int j;Insect() {print("i = " + i + ", j = " + j);j = 39;}private static int x1 =printInit("static Insect.x1 initialized");static int printInit(String s) {print(s);return 47;}
}public class Beetle extends Insect {private int k = printInit("Beetle.k initialized");public Beetle() {print("k = " + k);print("j = " + j);}private static int x2 =printInit("static Beetle.x2 initialized");public static void main(String[] args) {print("Beetle constructor");Beetle b = new Beetle();}
} /* Output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*///:~
7.10总结
如果将项目视作是有机的,进化着的生命体去培养,而不是打算像盖摩天大楼一样快速见效,就会获得更多的成功和更迅速的回馈。
《java编程思想》第七章 复用类相关推荐
- java学习笔记 java编程思想 第7章 复用类
文章目录 7.1 组合语法 练习1 7.2 继承语法 7.2.1 初始化基类 练习3 练习4 练习5 带参数的构造器 练习6 练习7 练习8 练习9 练习10 7.3 代理 练习11 7.4 结合使用 ...
- 《java编程思想》学习笔记——复用类
2019独角兽企业重金招聘Python工程师标准>>> 1.复用类的两种方法 (1)只需在新的类中产生现有类的对象.由于新的类是由现有类的对象所组成,所以这种方法称为组合.该方法只是 ...
- java编程思想初始化引用,JAVA编程思想--第5章 初始化与清理
随着计算机革命的发展,"不安全"的编程方式已逐渐成为编程代价高昂的主因之一. 初始化和清理(cleanup)是涉及安全的两个问题.初始化时,忘记初始化时许多错误的来源,还有就是不知 ...
- Java编程思想(第十一章持有对象)
1. 第11章 持有对象 java通过使用容器类来储存对象,与普通数组不同的是,普通数组的长度不可变. 1.1. 泛型与类型安全的容器 使用预定义的泛型,它指定了这个容器实例可以保存的类型,通过使用泛 ...
- Java编程思想 第十三章:字符串
1.不可变String String对象是不可变的,每一个看似修改了String值的方法,实际上都是创建了一个全新的String对象. public class Immutable {public s ...
- java学习笔记 java编程思想 第6章 访问权限控制
文章目录 6.1 包:库单元(the library unit) 6.1.1 代码组织 6.1.2 创建独一无二的包名 练习1 练习2 6.1.3 定制工具类 6.1.4 用import改变行为 练习 ...
- Java编程思想第十一章持有对象的11.1~11.4小节的笔记和练习题
11.1 泛型和类型安全的容器 在JavaSE5之前的容器,编译器允许我们向容器中放入不正确的类型.诸如,有一个Apple对象的容器,它是一个ArrayList,而我们也可以往它里面放入一个O ...
- 【转】java编程思想第20章的注解例子用到的com.sun.mirror的jar包
Java編程思想>中的注解代码中引入过这么一个包(com.sun.mirror),书上说的是在Jdk中有个tools.jar中,引入这个包就每这个问题了,但是笔者用的是JDK 1.8,把这个包i ...
- java代码程序流程思想_控制执行流程——java编程思想第4章
开篇:就像有知觉的生物一样,程序必须在执行过程中控制它的世界,并做出选择,在java中,你要使用执行控制语句来做出选择. 4.1:true和false 所有条件语句都利用条件表达式的真或假来决定执行路 ...
最新文章
- 【Qt】pro 笔记
- Autodesk MotionBuilder 2020中文版
- Win服务器2008和2012哪个更好?
- [CVPR2016]Learning Deep Feature Representations with Domain Guided Dropout for Person Re-id
- python自建包的根目录可以直接import的方法
- 实战|渗透学校某内网服务器
- php 置信区间 计算,科学网—置信区间和标准误差 - 邸月宝的博文
- Python基础:获取迭代器下一项目的常见操作
- php 首页加背景图片,如何在页首添加一张背景图片
- 媒体查询笔记、 @media
- LeetCode 237. Delete Node in a Linked List
- linux下识别内存,c – Linux:识别内存中的页面
- Oracle八大性能视图之v$transaction
- SC2012 Orchestrator - 文档及资源链接
- Traffic Server中的cache.config的字段理解
- 递归--练习11--noi9273 PKU2506Tiling
- 转载:CS224n笔记1 自然语言处理与深度学习简介
- 遍历上三角或者下三角
- R语言 循环 步长 写法
- 用计算机画图教案评价,电脑画图教案