《Thinking in java》-学习笔记(7)

学习第七章的笔记如下:

七.第七章 多形性

        讲一下自己的一些体会理解:

(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)如果没有绑定,就不称其为多形性。

一句话总结:通过抽象类和抽象方法,接口,内部类,动态绑定(后期绑定),上溯造型来应用多形性。

猜你喜欢

转载自blog.csdn.net/a614528195/article/details/81114444