Think in java第七章笔记

1.通过继承可将一个对象当做它自己的类型或者它自己的基础类型对待。这种能力是非常重要的,因为多个类型(从相同的基础类中衍生出来)可被当做同一类型对待。而且只需要一段代码,即可对所有不同的类型进行同样的处理。

2.将一个方法调用同一个方法主体连接到一起就称为绑定。若一种语言实现了动态绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对动态绑定的实现时由区别的。但它们都要在对象中安插某些特殊类型的信息。

3.为什么要把一个方法声明成final呢?它能防止其他人覆盖那个方法。更重要的是,它可有效的"关闭"动态绑定,或者告诉编译器不需要进行动态绑定。这样就可为final方法调用生成效率更高的代码。

4.使用动态绑定后,所有的衍生类都能保证用相同的代码正常的工作。我们可以"将一条消息发送给一个对象,让对象自行判断要做什么事情"。

5.包含了抽象方法的一个类叫做"抽象类"。如果一个类里包含了一个或多个抽象方法,类就必须指定成abstract。如果从一个抽象类继承,而且想生成新类型的一个对象,就必须为基础类中的所有抽象方法提供方法定义。

6.可决定将一个接口中的方法声明明确定义为"public"。但即使不明确定义,它们也会默认为public。所以在实现一个接口的时候,来自接口的方法必须定义成public。否则,它们会默认为"友好的"。

7.

interface CanFight {
	void fight();
}
interface CanSwim{
	void swim();
}
interface CanFly{
	void fly();
}
class ActionCharacter {
	public void fight() {
		
	}
}

class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly {
	public void swim() {
		
	}
	public void fly() {
		
	}
}
public class Adventure {

	static void t(CanFight x) {
		x.fight();
	}
	static void u(CanSwim x) {
		x.swim();
	}
	static void v(CanFly x) {
		x.fly();
	}
	static void w(ActionCharacter x) {
		x.fight();
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Hero i = new Hero();
		t(i); //Treat it as a CanFight
		u(i); //Treat it as a CanSwim
		v(i); //Treat it as a CanFly
		w(i); //Treat it as an ActionCharacter
	}

}

尽管Hero没有为fight明确地提供一个定义,但定义时随同ActionCharacter来的,所以这个定义会自动提供,我们可以创建Hero的对象。

接口的作用:能上溯至多个基础类型;防止客户程序员制作这个类的一个对象。如果事先知道某种东西会成为基础类,那么第一个选择就是把它变成一个接口。只有在必须使用方法定义或者成员变量的时候,才应考虑采用抽象类。


8.

interface Content {
	void fly();
}

class Contents implements Content {
	public void fly() {
		
	}
}
public class Parcel6 {
	public Contents count() {
		return new Contents() {
			private int i = 11;
			public int value() {
				return i;
			}
		};
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Parcel6 p = new Parcel6();
		Contents c = p.count();
	}

}

return new Contents() {
			private int i = 11;
			public int value() {
				return i;
			}
		}
要表达的意思是:创建从Contents衍生出来的匿名类的一个对象。由new表达式返回的句柄会自动上溯造型成一个Contents句柄。匿名内部类的语法其实要表达的是:

class MyContents extends Contents {
	private int i = 11;
	public int value() {
		return i;
	}
}

return new MyContents();

9.

class Destination {
	
}
public class Parcel8 {
	public Destination dest(final String dest) {
		return new Destination() {
			private String label = dest;
			public String readLable() {
				return label;
			}
		};
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Parcel8 p = new Parcel8();
		Destination d = p.dest("Tanzania");
	}

}

若试图定义一个匿名内部类,并想使用在匿名内部类外部定义的一个对象,则编译器要求外部对象为final属性。


10.创建自己的内部类时,那个类的对象同时拥有指向封装对象的一个链接。所以能访问那个封装对象的成员。

11.

class WithInner {
	class Inner{
		
	}
}
public class InheritInner extends WithInner.Inner{
	InheritInner(WithInner wi) {
		wi.super();
	}
	/*InheritInner() {
		
	}*/
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		WithInner wi = new WithInner();
		InheritInner ii = new InheritInner(wi);
	}

}

内部类构建器必须同封装类的对象的一个句柄联系到一起。从一个内部类继承的时候,情况会变得复杂。封装类的"秘密"句柄必须获得初始化,而且在衍生类中不再有一个默认的对象可以连接。

12.

class Egg2 {
	protected class Yolk {
		public Yolk() {
			System.out.println("Egg2.Yolk()");
		}
		public void f() {
			System.out.println("Egg2.Yolk.f()");
		}
	}
	private Yolk y = new Yolk();
	public Egg2() {
		System.out.println("New Egg2()");
	}
	public void insertYolk(Yolk yy) {
		y = yy;
	}
	public void g() {
		y.f();
	}
}
public class BigEgg2 extends Egg2{
	public class Yolk extends Egg2.Yolk {
		public Yolk() {
			System.out.println("BigEgg2.Yolk()");
		}
		public void f() {
			System.out.println("BigEgg2.Yolh.f()");
		}
	}
	public BigEgg2() {
		insertYolk(new Yolk());
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Egg2 e2 = new BigEgg2();
		e2.g();
	}

}
输出为:

Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolh.f()

13.由于每个类都会生成一个.class文件,用于容纳如何创建这个类型的对象有关的所有信息(这种信息产生了一个名为Class对象的元类)。内部类也必须生成相应的.class文件,用来容纳它们的Class对象的有关信息。这些文件或类的名字遵守一种严格的形式:先是封装雷丁额名字,再跟随一个¥,再跟随内部类的名字。


14.

class Meal{
	Meal() {
		System.out.println("Meal()");
	}
}
class Bread{
	Bread() {
		System.out.println("Bread()");
	}
}
class Cheese{
	Cheese() {
		System.out.println("Cheese()");
	}
}
class Lettuce {
	Lettuce() {
		System.out.println("Lettuce()");
	}
}
class Lunch extends Meal {
	Lunch() {
		System.out.println("Lunch()");
	}
}
class PortableLunch extends Lunch {
	PortableLunch() {
		System.out.println("PortableLunch()");
	}
}
public class SandWitch extends PortableLunch{

	Bread b = new Bread();
	Cheese c = new Cheese();
	Lettuce l = new Lettuce();
	SandWitch() {
		System.out.println("SandWitch");
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new SandWitch();
	}

}

Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
SandWitch

对于一个复杂的对象,构建器的调用遵循:

(1)调用基础类的构建器。这个步骤会不断重复下去,首先得到构建器的是分级结构的根部,然后是下一个衍生类,等等。直到抵达最深一层的衍生类。

(2)按声明顺序调用成员初始化模块。

(3)调用衍生构建器的主体。

当我们在衍生类的时候,必须能假定基础类的所有成员都是有效的。但在构建器内部,必须保证使用的所有成员都已构建。所以,首先调用基础类的构建器,然后在进入衍生类构建以后,我们在基础类能够访问的所有成员都已得到初始化。


15.构建器的职责是让对象实际进入存在状态。在任何构建器内部,整个对象可能只是得到部分组织——我们只知道基础类对象已得到初始化,但不知道哪些类已经继承。然而一个动态绑定的方法调用却会在分级结构里"向前"或"向外"进行。

初始化的实际过程是这样的:

(1)在采取任何其他操作之前,为对象分配的存储空间初始化成二进制0.

(2)调用基础构建器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值