Practicle Java笔记 实践59-68(完)

 

实践59

运用interfaces支持多重继承

实践60

没有任何办法能够阻止两个interfaces使用同名的常数和函数,为了避免可能的冲突,应当小心命名常数和函数。

例如例子中给出的 interface Golf和interface Bowling都有computeScore在实现时 为了加以区分 只能再额外创建一个MyGolf或MyBowling 之后让类实现MyGolf/MyBowling来区分开2者间的计算(在使用不同程序提供的接口时可能会出现这种情况)

实践61

如需提供部分实现(partial implementation),请使用抽象类(abstract classes),这些实现很可能对derived class是共通的

实践62

理解和区分interface,abstract class和concrete class之间的差异

interface内函数默认public,常量默认public static final

实践63

谨慎定义和实现不可变类(immutable classes)

如果你希望对象内容永远不被改动,请使用不可变对象(immutable object),这种对象自动拥有“多线程安全性”。

1 将class中所有的数据声明为private 

2 只提供取值函数,而不允许存在setter

3 声明class为final (放置被子类化 而子类复写getter或setter)

4 从获取器返回reference给可变对象时,先克隆可变的对象

5 将传递给构造函数的可变对象reference先克隆一份

6 在构造函数中设定class内含的所有数据

实践64

如果不实施克隆动作,你的对象不变性(immutability)就得不到保证。这是因为他处可能保留了这个immutable object 内的某个object 的reference,并对其进行了修改,从而冲破了不变性的[界限]。

考虑一个情况 final class内部有一个非final的对象 而在其中改变了该非final对象的内部属性 由于保存的是reference的关系 final class的object必然也被改变了(就是这种情况)

所以欲传递或接收可变对象(mutable objects)的object references时,请使用clone()。为了保证immutable objects,你必须在传入和回传它们时对它们施行clone()。

注意:Vector实现的clone是浅克隆,如果需要,必须自己实现深克隆版本,例如

 

	public Object clone(){
		ShareVector v=(ShareVector)super.clone();
		int size=size();
		for(int i=0;i<size;i++){
			User u=(User)(this.get(i));
			v.setElementAt((User)(u.clone()),i);
		}
		return v;
	}

还有一种修改方法,由类自己,克隆所含的对象,提供方法

 

	private Vector cloneVector(Vector v){
		int size=v.size();
		Vector newVector=new Vector(size);
		for(int i=0;i<size;i++){
			newVector.add(((User)v.get(i)).clone());
		}
		return newVector;
	}

  实现一个immutable class不可变类时,遵循下列规则

1 声明这个class为final

2 声明所有数据为private

3 只提供取值函数getter,不提供设值函数setter

4 在构造函数中设置所有instance数据

5 如果函数返回reference to mutable objects,请克隆那些mutable objects

6 如果函数接收reference to mutable objects,请克隆那些mutable objects

7 如果缺省之浅层克隆不能符合immutable object的正常幸会,请实现出深层克隆。

实践65

3种可以用来定义immutable classes的技术:

1 immutable interface 不可变接口

2 公共接口或基类 common interface or base class

3 immutable delegation class 不可变的委托类

使用不可变接口:

 

	interface ImmutableCircle{
		public double radius();
	}
	class MutableCircle implements ImmutableCircle{
		private double radius;
		public MutableCircle(double r){
			radius=r;
		}
		public void setRadius(double r){
			radius=r;
		}
		public void double radius(){
			return radius;
		}
	}
	public class Test{
		public ImmutableCircle createWheel(double r){
			return new MutableCircle(r);
		}
		public static void main(String args[]){
			Test t=new Test();
			ImmutableCircle iWheel=t.createWheel(5.0);
			iWheel.setRadius(7.4); //Error
		}
	}

由于iWheel是ImmutableCircle类型 只暴露了radius方法,因此自然不能调用setRadius

但是要注意的是,当使用

((MutableCircle)iWheel).setRadius(7.4);

转型后 应当Immutable的Circle被改变了。

使用公共接口或公共基类:

1 一个公共基类/接口,其内声明一些可被其derived classes共享的immutable函数

2 一个derived class,提供mutable函数实现代码

3 另一个derived class,提供immutable函数实现代码

 

	interface PinNumbers{
		public String accountOwner();
		public int checkingPin();
		public int savingPin();
	}
	class MutablePinNumbers implements PinNumbers{
		private String acctOwner;
		private int checkingAcctPin;
		private int savingAccPin;
		MutablePinNumbers(String owner,int cPin,int sPin){
			acctOwner=owner;
			checkingAcctPin=cPin;
			savingAccPin=sPin;
		}
		//下面提供各自的getter和setter方法 总共6个
	}
	final class ImmutablePinNumbers implements PinNumbers{
		private String acctOwner;
		private int checkingAcctPin;
		private int savingAccPin;
		ImmutablePinNumbers(String owner,int cPin,int sPin){
			acctOwner=owner;
			checkingAcctPin=cPin;
			savingAccPin=sPin;
		}
		//下面只提供3个getter方法
	}

上述方式的实现可以确保不可变性,不会被简单的转型打破

不可变的委托类:

使用immutable delegation class,其中只包含immutable methods,并将外界对他们的调用任务委托给class内含的mutable object

 

	class MutableCircle{
		private double radius;
		public MutableCircle(double r){
			radius=r;
		}
		public void setRadius(double r){
			radius=r;
		}
		public double radius(){
			return radius;
		}
	}
	final class ImmutableCircle{
		private MutableCircle mCircle;
		public ImmutableCircle(double r){
			mCircle=new MutableCircle(r);
		}
		pbulic double radius(){
			return mCircle.radius();
		}
	}

  这样外界只能调用radius方法 其实是通过内部的可变对象调用

但是这种做法让你需要在实现委托模型和维护上花更大的力气,并且每次调用委托函数,都会付出性能上的代价

三者直接的优劣区别:

使用不可变接口:

优点:简单易行,无需付出性能上的代价

缺点:有破绽,通过转型可以破坏

使用公共接口或基类

优点:没有破绽,清晰地将mutable object和immutable objects分离

缺点:需要实现更多的classes,完成更深的classes继承关系

使用不可变的委托类

优点:没有破绽,当无法修改既有mutable object源代码时,此法可用

缺点:需要付出性能上的代价

实践66

当你实现一个clone(),总是应该调用super.clone()以确保产生正确的对象。

当打算实现深层克隆的时候,这条规则也同样适用。

 

	class House implements Cloneable{
		//...
		public Object clone(){
			try{
				return super.clone();
			}catch(CloneNotSupportedException e){
				throw new InternalError();
			}
		}
	}

实践67

不要把希望寄托于finalize()被调用。应当实现自己的non-memory资源清理机制,然后结合class的finalize()一道使用。确信需要如此清理的class必然包含一个public函数,专门负责释放资源,这个函数应当被class的finalize()调用,以确保当JVM调用finalize()时能够释放non-memory资源。如果finalize()未被调用,用户可以直接调用这个public函数。

 

	class Communication{
		private ServerSocket ss;
		private FileInputStream fileIn;
		//...
		public synchronized void cleanup() throws IOException{	//确保多线程不会针对相同对象进入该函数 
			is(ss!=null){	//检查是否为null,在close后置为null,保证不会重复调用close
				ss.close();
				ss=null;
			}
			if(fileIn!=null){
				fileIn.close();
				fileIn=null;
			}
		}
	}
	protected void finalized() throws Throwable{
		try{
			cleanup();
		}finally{
			super.finalize();	//所有的finlize都应当调用super.finalize()
		}
	}

实践68

如果一个non-final函数被某个derived class覆盖,在构造函数中调用这个函数可能会导致不可预期的结果。

看一个例子:

 

	class Base{
		private int val;
		Base{
			val=lookup();
		}
		public int lookup(){
			return 5;
		}
		public int value(){
			return val;
		}
	}
	class Derived extends Base{
		private int num=10;
		public int lookup(){
			return num;
		}
	}
	class Test{
		public static void main(String args[]){
			Derived d=new Derived();
			System.out.println(d.value());
		}
	}

这里打印的结果是0!

这与预期的结果10不符,原因在于lookup函数是在Derived对象建构期间由Base构造函数调用的,当进入Derived的lookup()时,其instance变量初始化行为还未被进行,因此使用了缺省值0。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值