JAVA编程思想学习总结:第七章——复用类

/*此总结的主要内容是我在学习JAVA过程中,认为需要记忆的知识点。并结合之前自己学习C++及javascript的相关知识,注明JAVA在一些情况下与这两门语言的相同及不同之处。*/

(1)组合

只需将对象引用置于新类中,即意味着组合。

(2)继承

package reusableClass;
//写该示例的原因是有次做笔试题,问到同时存在两个main函数时运行会出现什么样的情况
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();
		System.out.println(x);
	}
}
public class Detergent extends Cleanser{
	public void scrub(){
		append(" Detergent.scrub()");
		super.scrub();//调用基类的方法
	}
	public void foam(){
		append(" foam()");
	}
	public static void main(String[] args){//测试同一个class文件中存在两个mian方法时的运行情况
		Detergent x=new Detergent();
		x.dilute();
		x.apply();
		x.scrub();
		x.foam();
		System.out.println(x);
		System.out.println("Testing base class:");
		Cleanser.main(args);
	}
	//在有两个main函数时,运行时需要选择究竟运行哪个类中的函数,无论选择哪个,都能正常运行。
}

继承的构建过程是从基类向外扩散的,所以基类在导出类构造器可以访问它之前,就已经完成了初始化。

不过这种初始化只会调用不带参数的基类。如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须用关键字super显式的编写调用基类构造器语句,并且配以适当的参数列表。注意,调用基类构造器必须是在导出类构造器中要做的第一件事。

package reusableClass;
//P130
class Game{
	Game(int i){
		System.out.println("Game constructor");
	}
}
class BoardGame extends Game{
	BoardGame(int i){
		super(i);
		System.out.println("BoardGame one  constructor");
	}
	BoardGame(int i,int j){
		super(i);
		//this(j);//测试用了super调用基类的构造函数后还能否用this调用自身的其它构造函数,结果是不能,
		//即在同一个构造函数中,使用了super调用基类的构造函数,就不能再用this调用自身的构造函数
		//但是可以考虑在该构造函数中利用this调用其它构造函数,然后用this调用的构造函数调用基类构造函数
		//this(i);
		System.out.println("BoardGame constructor");
	}
}
public class Chess extends BoardGame{
	Chess(){
		super(11);
		System.out.println("Chess  constructor");
	}
	public static void main(String[] args){		
	//public static void main(String[] args){
		Chess x=new Chess();
	}
}

PS:在想覆写基类的某个方法时,可以选择添加这个注解,防止不想重载时意外的进行了重载。

(3)代理

这是继承与组合之间的中庸之道。通过实验成员对象的中一部分方法,即能对成员对象有一定的控制力,又能避免暴露成员对象的所有方法。

(4)组合与继承之间的选择

组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形,往往意味着has-a关系。
继承是使用一个通用类,并为了某种特殊需要而将其特殊化,往往意味着is-a关系。
如果需要一个新类向基类进行向上转型,那么继承是必要的。但是如果不需要,则应当好好考虑是否需要继承。

(5)protected关键字(补充上一章内容)

该关键字指明就类用户而言,这是private的,但是对于像模像样继承于此类的导出类或其他任何类或其他任何位于同一个包内的类来说,它确是可以访问的。因为该关键字提供了包访问权限。

(6)向上转型

向上转型即将导出类转型成基类,这在继承图上是向上移动的,所以称为向上转型。
在向上转型的过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取它们。这就是为什么编译器在“未曾明确表示转型”或“未曾指定特殊标记”的情况下,仍然允许向上转型的原因。

(7)final关键字

1、final数据:这意味着一个永不改变的编译时常量,一个在运行时被初始化的值 ,并且不希望被改变。不过对于引用来说,final使引用恒定不变,一旦引用被初始化指向一个对旬,就无法再把它改为指向另一个对象。但是,对象自身却是可以被修改的。虽然java并未提供使任何对象恒定不变的途径,但是可以通过将所有数据定义成private,并且不提供方法对数据进行修改实现。
即使某数据是final的,也不能认为在编译时就知道它的值,因为可以采用随机数生成函数对其赋值。
允许数据被声明为final但是不在声明时给定初值,不过编译器会确保这样的数据在使用前被初始化——必须在定义处或者构造器中初始化。
2、final参数:这意味着该参数无法在方法中更改参数引用所指向的对象。
3、final方法:
用处一:把方法锁定,以防任何继承类修改它的含义,这是出于设计的考虑,想要确保在继承中使方法行为保持不变,并且不会被覆盖。
用处二:效率。该方法的调用将转为内嵌,不过现在这种使用方法逐渐不被考虑。
private方法都会隐式地指定为final方法。
4、final类:当将某个类定义为final类时,意味着该类不能被继承类。由于final类禁止继承,所以final类中所有方法都隐匿指定为final,而无法覆盖。
慎用final方法以及final类。

(8)初始化及类的加载

类的代码在初次使用时才加载。这通常是指加载发生于创建类的第一个对象之时,但是当访问static域或Static方法时,也会发生加载。
其实构造器也是Static方法,尽管static并没有显式的写出来。所以更准确地讲,类是在其任何static成员被访问时加载的。
package reusableClass;
//P146
/*程序运行过程
 * (1)首先会试图访问main函数
 * (2)访问main函数时,会开始加载main函数所在的类Beetle
 * (3)如果现在加载的类有基类,会继续加载基类,持续此过程,直到加载到根基类
 * (4)从根基类开始沿继承链向上依次初始化类中的static声明
 * (5)必要的类被加载完毕后,才会开始运行main函数
 * (6)创建不带main函数的其它类过程类同(3)(4),接下来才可以创建类对象,首先,对象中的所有基本类型会被设为默认值。然后,构造器才可以被调用。构造器调用也会沿继承链
 * 先不断上溯直到根基类,再依继承链顺序执行构造器的其余部分
 */

class Insect{
	private int i=9;
	protected int j;
	Insect(){
		System.out.println("i="+i+",j="+j);
		j=39;
	}
	private static int x1=printInit("static Insect.x1 initialized");
	static int printInit(String s){
		System.out.println(s);
		return 47;
	}
}
public class Beetle extends Insect{
	private int k=printInit("beetle.k initialized");
	public Beetle(){
		System.out.println("k="+k);
		System.out.println("j="+j);
	}
	private static int x2=printInit("static Beetle.x2 initialized");
	public static void main(String[] args){
		System.out.println("main start run");
		Beetle b=new Beetle();
	}
}

总结中有一段话,是我学习这一章的最大收获。
当你开始设计一个系统时,应该认识到程序感叹句一种增量过程,犹如人类的学习一样,这一点很重要,程序开发依赖于实验,你可以尽能去分析,但当你开始执行一个项目时,仍然无法知道所有的答案。如果将项目视作一种有机的,进化着的生命体去培养,而不是打算像盖摩天大楼一样快速见效,就会获得更多的成功和更讯速的回馈。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章