学习第七章的笔记如下:
七.第七章 多形性
讲一下自己的一些体会理解:
(1) “多形性”将接口从具体的实施细节中分离出来,实现了“是什么”与“怎么做”两个模块的分离。
(2)上溯造型:取得对象句柄,并将其作为基础类型句柄使用的行为。
Shape s=new Circle();
上面这个例子中创建了一个Circle对象,赋值给基础类句柄s。这种行为就是上溯造型。
(3)方法调用的绑定:将一个方法的调用同一个方法主体连接到一起就称为绑定。Java中绑定的所有
方法都采用后期绑定技术。把方法声明成final可以有效有效地关闭动态绑定。
package exam;
import oypj.tools.*;
interface Rodents{
void eat();
int e=1;
}
class Mouse implements Rodents{
public void eat(){
P.rintln("Mouse.eat()");
}
}
class Gerbil implements Rodents{
public void eat(){
P.rintln("Gerbil.eat()");
}
}
class Hamster implements Rodents{
public void eat(){
P.rintln("Hamster.eat()");
}
}
public class Rodent {
public static Rodents select(){
switch((int)(Math.random()*3)){
default:
case 0: return new Mouse();
case 1: return new Gerbil();
case 2: return new Hamster();
}
}
public static void main(String[] args){
Rodents[] rodent=new Rodents[10];
for(int i=0;i<rodent.length;i++)
rodent[i]=select();
for(int i=0;i<rodent.length;i++)
rodent[i].eat();
}
}
(4)扩展性:由于存在多形性,可以根据自己需要向系统里加入任意的新类型,不用修改原来的方法
模型。
(5)抽象类和方法:若想通过该通用接口处理一系列类,就需要创建一个抽象类。对所有与基础类声
明的签名相符的衍生类方法,都可以通过动态绑定机制调用。抽象方法在抽象类中定义。不能创建抽象
类的实例。继承抽象类必须实现基类的所有抽象方法,否者衍生类也是抽象的。
(6)接口:是一个更“纯”的抽象类,接口中的基本数据类型的数据成员,都默认为static和final。接口中
的方法默认为public。接口一般用于建立类和类之间的一个“协议”。使用接口的原因是:能上溯到多个基
础类,防止客户程序员制作这个类的对象。
(7)Java的“多重继承”:一个类只能继承一个类,但是可以继承多个接口。
(8)如果知道某种东西会成为基础类,那么第一选择就是把它变成一个接口,只有在必须使用方法定义
或者成员变量的时候,才考虑采用抽象类。
(9)通过继承接口来扩展接口,在接口中可以继承多个接口。
interface Animal{
void eat(){}
}
interface Animals extends Animal{
void play(){}
}
(10)接口可以对常数值进行分组,接口中的字段都默认为static final
public interface Math{
doudou PI=3.1415926;
}
注意拥有固定标识符的static final 基础数据类型都全部采用大写字母,用下划线分隔多个单词。
(11)内部类:在一个类里面再定义一个类。内部类可以标识为private、protected。利用private内部类
,类设计者可以完全禁止其他人依赖类型编码,可以把具体的实施细节完全隐藏起来。
(12)可以在方法内定义类或者任意的作用域内创建内部类。
(13)匿名内部类,要使用匿名内部类外部定义的一个对象,外部对象必须为 final属性。可以使用外部
定义的对象来为匿名内部类创建构建器。
public class Parcel{
public Destination dest(final String dest,final float price){
return new Destination(){
private int cost;
/** 构建器 */
{
cost=Math.round(price)
}
private String label=dest;
};
}
}
(14)内部类可以访问封装对象的成员,也就是可以访问外部类的成员。
(15)static内部类可以用在接口中
interface Animal{
static class Inner{
int i,i,k;
public Inner(){}
}
}
(16)用static内部类容纳自己的测试代码
class Test{
Test(){}
void play(){}
public static class Tester{
public static void main(String[] args){
Test t=new Test();
t.play();
}
}
}
这里生成了一个Test¥Tester的类,运行程序时使用 java Test¥Tester 指令。
(17)引用外部类对象:若想生成外部类对象的句柄,就要用一个点号以及一个this 来命名外部类。举个例子来说,在
Sequence.SSelector 类中,它的所有方法都能产生外部类Sequence 的存储句柄,方法是采用Sequence.this
的形式。
(18)创建内部类的对象,必须在new表达式中提供指向外部类对象的句柄
Parcel p=new Parcel();
Parcel.Contents c=p.new Contents();
(19)从内部类继承的时候,在构建器中必须使用 "内部类的外部类.super()"
(20)内部类可以一简化控制框架的创建与使用,控制框架的设计宗旨是将不同的代码方便地隔离开。下面是书上的例
子,可以帮助理解。
package exam;
abstract public class Event {
private long evtTime;
public Event(long eventTime){
evtTime=eventTime;
}
public boolean ready(){
return System.currentTimeMillis()>=evtTime;
}
abstract public void action();
abstract public String description();
}
package exam;
class EventSet{
private Event[] events=new Event[100];
private int index=0;
private int next=0;
public void add(Event e){
if( index>=events.length)
return;
events[index++]=e;
}
public Event getNext(){
boolean looped=false;
int start=next;
do{
next=(next+1)%events.length;
if(start==next) looped=true;
if((next==(start+1)%events.length)&&looped)
return null;
} while(events[next]==null);
return events[next];
}
public void removeCurrent(){
events[next]=null;
}
}
public class Controller {
private EventSet es=new EventSet();
public void addEvent(Event c){es.add(c);}
public void run(){
Event e;
while((e=es.getNext())!=null){
if(e.ready()){
e.action();
System.out.println(e.description());
es.removeCurrent();
}
}
}
}
package exam;
public class GreenhouseControls extends Controller{
private boolean light=false;
private boolean water=false;
/** run 是风扇开关的标志,false为关闭,true为打开 */
private boolean run=false;
private String thermostat="Day";
private class RunOn extends Event{
public RunOn(long eventTime){
super(eventTime);
}
public void action(){
run=true;
}
public String description(){
return "Run is on";
}
}
private class RunOff extends Event{
public RunOff(long eventTime){
super(eventTime);
}
public void action(){
run=false;
}
public String description(){
return "Run is off";
}
}
private class LightOn extends Event{
public LightOn(long eventTime){
super(eventTime);
}
public void action(){
light=true;
}
public String description(){
return "Light is on";
}
}
private class LightOff extends Event{
public LightOff(long eventTime){
super(eventTime);
}
public void action(){
light=false;
}
public String description(){
return "Light is off";
}
}
private class WaterOn extends Event {
public WaterOn(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
water = true;
}
public String description() {
return "Greenhouse water is on";
}
}
private class WaterOff extends Event {
public WaterOff(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
water = false;
}
public String description() {
return "Greenhouse water is off";
}
}
private class ThermostatNight extends Event {
public ThermostatNight(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
thermostat = "Night";
}
public String description() {
return "Thermostat on night setting";
}
}
private class ThermostatDay extends Event {
public ThermostatDay(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
thermostat = "Day";
}
public String description() {
return "Thermostat on day setting";
}
}
private int rings;
private class Bell extends Event {
public Bell(long eventTime) {
super(eventTime);
}
public void action() {
// Ring bell every 2 seconds, rings times:
System.out.println("Bing!");
if(--rings > 0)
addEvent(new Bell(
System.currentTimeMillis() + 2000));
}
public String description() {
return "Ring bell";
}
}
private class Restart extends Event{
public Restart(long eventTime){
super(eventTime);
}
public void action(){
long tm=System.currentTimeMillis();
rings=5;
addEvent(new ThermostatNight(tm));
addEvent(new LightOn(tm+1000));
addEvent(new LightOff(tm+2000));
addEvent(new RunOn(tm+2100));
addEvent(new RunOff(tm+2600));
addEvent(new WaterOff(tm+8000));
addEvent(new WaterOn(tm+3000));
addEvent(new Bell(tm+9000));
addEvent(new ThermostatDay(tm+10000));
addEvent(new Restart(tm+2000));
}
public String description(){
return "Restarting system";
}
}
public static void main(String[] args){
GreenhouseControls gc=new GreenhouseControls();
long tm=System.currentTimeMillis();
gc.addEvent(gc.new Restart(tm));
gc.run();
}
}
(21)构建器和多形性:构建器的调用顺序
原文代码
package exam;
import oypj.tools.*;
class Meal{
Meal(){ P.rintln("Meal()");}
}
class Bread{
Bread(){ P.rintln("Bread()");}
}
class Cheese{
Cheese(){ P.rintln("Cheese()");}
}
class Lettuce{
Lettuce(){ P.rintln("Lettuce()");}
}
class Lunch extends Meal{
Lunch(){ P.rintln("Lunch()");}
}
class PortableLunch extends Lunch{
PortableLunch(){
P.rintln("PortabelLunch()");
}
}
public class Sandwich extends PortableLunch {
Bread b=new Bread();
Cheese c=new Cheese();
Lettuce l=new Lettuce();
Sandwich(){
P.rintln("Sandwich()");
}
public static void main(String[] args){
new Sandwich();
}
}
输出结果
Meal()
Lunch()
PortabelLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
构建器调用遵循下面的顺序:
(1)在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零。
(2) 调用基础类构建器。这个步骤会不断重复下去,首先得到构建的是分级结构的根部,然后是下一个衍生
类,等等。直到抵达最深一层的衍生类。
(3) 按声明顺序调用成员初始化模块。
(4) 调用衍生构建器的主体。
(22)覆盖衍生类的finalize()时,要调用finalize()的基础类版本,否则基础类初始化不会发生。
(23)合成,可以动态选择一种类型(或行为),而继承要求在编译期间准确知道一种类型。用继承表达行为间的差异
,用成员变量表达状态的变化。
(24)下溯造型与运行期类型标识:运行期间对类型进行检查的行为叫作“运行期类型标识”(RTTI)。
原文代码
package exam;
class Useful{
public void f(){}
public void g(){}
}
class MoreUseful extends Useful{
public void f(){}
public void g(){}
public void u(){}
public void v(){}
public void w(){}
}
public class RTTI {
public static void main(String[] args){
Useful[] x={new Useful(),new MoreUseful()};
x[0].f();
x[1].g();
((MoreUseful)x[1]).u();
}
}
(25)如果没有绑定,就不称其为多形性。
一句话总结:通过抽象类和抽象方法,接口,内部类,动态绑定(后期绑定),上溯造型来应用多形性。