《编程思想》6.复用类

1.每个编译单元都必须有一个后缀名.java,而在编译单元则可以有一个public类,每个编译单元只能有一个public类,否则编译器就会接受

2.组合语法:只需将对象引用置于新类中即可。

public class WaterSource {
	private String s ;
	WaterSource(){
		System.out.println("WaterSource()");
		s = "Construceted";
	}
	
	public String toString() {
		return s ;
	}
}

public class ArrayMaker {
	private String valve1,valve2,valve3,valve4; //第一执行
	
	private WaterSource source = new WaterSource(); //第二执行
	
	private int i ;
	private float f ;
	public String toString(){
		return 
				"valve1=" + valve1 + "" +
				"valve2=" + valve2 + "" +
				"valve3=" + valve3 + "" +
				"valve4=" + valve4 + "\n"+
				"i = " + i + "" + "f = "+f+""+
				"source = " + source ;
	}

	public static void main(String[] args) { //最后执行
	   ArrayMaker arrayMaker = new ArrayMaker();
	   System.out.println(arrayMaker);
	}
 
}

(1)每一个非基本类型的对象都有一个toString()方法,而且当编译器需要一个String而你却只有一个对象时,该方法便会被调用。

2.继承语法

public 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;
	}

	//即使是一个程序中含有多个类,也只有命令行所调用的那个类的main()方法会被调用
	public static void main(String[] args) {
		 
		 Cleanser x = new Cleanser();
		 x.dilute();
		 x.apply();
		 x.scrub();
		 System.out.println(x);
	}

}


//继承先执行基类Cleaner
public class ArrayMaker extends Cleanser{
	public void scrub(){
		append("Detergent.scrub()--");
		//表达式super.scrub()将调用基类版本的scrub()方法
		super.scrub();
	}
	
	public static void main(String[] args) {
		ArrayMaker x = new ArrayMaker();
		x.dilute();
		x.apply();
		x.scrub(); 
		System.out.println(x);
		System.out.println("Testing base class: ");
		//Cleanser.main(args);
	}
 
}

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

class Art {
	Art(){ print("Art constructor");}
}

class Drawing extends Art{
	Drawing(){ print("Drawing constructor");}
}

public class Cartoon extends Drawing{
	public Cartoon(){ print("Cartoon constructor"); }
	public static void main(String[] args){
	   Cartoon x = new Cartoon();
	   }
	 }
	 //output : Art constructor  Drawing constructor  Cartoon constructor

4.调用一个带参数的基类构造器,就必须用关键字super显式地编写调用基类构造器的语句。

public class Game {
	Game(int i){
		System.out.println("Game constructor"); //第一个执行
	}
}

public class BoardGame extends Game {

	BoardGame(int i) {
		super(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) {
		 Chess x = new Chess();
	}

}

5.代理

public class SpaceShipControls {
		void up(int velocity){};
		void down(int velocity){};
		void left(int velocity){};
		void right(int velocity){};
		void forward(int velocity){};
		void back(int velocity){};
		void turboBoost(){};
}

//代理
public class MainJava {
    private String name;
    private SpaceShipControls controls = 
    		new SpaceShipControls();
    public MainJava(String name){
    	this.name = name ;  
    }
    
    public void back(int velocity){
    	controls.back(velocity);
    }
    
    public void down(int velocity){
    	controls.down(velocity);
    }
    //....省略方法
	public static void main(String[] args) {
		 MainJava protector = 
				 new MainJava("NSEA Protector");
		 protector.back(100);
	}

}

6.名称屏蔽
如果Java的基类拥有某个已被多次重载的方法名称,那么在导出中重新定义该方法名称并不会屏蔽其在基类中的任何版本。

public class Milhouse { 
}

public class Homer {
	char doh(char c){  //接收char
		System.out.println("doh(char)");
		return 'd';
	}
	
	float doh(float f){ //接收float
		System.out.println("doh(float)");
		return 1.0f;  
	}
}

public class Bart extends Homer{
	void doh(Milhouse m){ //接收Milhouse
		System.out.println("doh(Milhouse)");
	}
}

public class MainJava extends Homer{ 
	public static void main(String[] args) {
		  Bart b = new Bart();
		  b.doh(1);
		  b.doh('x');
		  b.doh(1.0f);
		  b.doh(new Milhouse());
	}

}

//doh(float)
//doh(char)
//doh(float)
//doh(Milhouse)
//所有重载方法都是可用的
//如果继承类和上一继承类都有相同构造方法,则选择继承类的

7.由于继承可以确保基类中所有的方法在导出类中也同样有效,所以能够向基类发送的所有消息同样也可以向导出类发送。
向上转型

class Instrument {
	public void play(){};
	static void tune(Instrument i){
	  i.play();
	  }
}

public class Wind extends Instrument {
	public static void main(String[] args){
	  Wind flute = new Wind();
	  Instrument.tune(flute);
	  }
}

8.final数据
(1)一个既是static又是final的域只占据一段不能改变的存储空间。
(2)对于基本类型,final使数值恒定不变,而用于对象引用,final使引用恒定不变,一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。
(3)定义为static,则强调只有一份;定义为fianl,则说明它是一个常量。带有恒定初始值的final static 基本类型全用大写字母命名,并且字与字之间用下划线隔开

public class MainJava { 
	private final int i = 0 ;
	private final int j ;
	private final Poppet p ;
	
	//必须在域的定义处或者每个每个构造器中用表达式对final进行赋值
	public MainJava(){
		j = 1 ;
		p = new Poppet(1);
	}
	public MainJava(int x){
		j = x ;
		p = new Poppet(x);
	}
	public static void main(String[] args) {
		new MainJava();
		new MainJava(47);
	}

}

(4)final参数
Java允许在参数列表中以声明的方式将参数指明为final。这意味着你无法在方法中更改参数引用所指向的对象:

	void with(final Gizmo g){
		g = new Gizmo();  //错误
	}

(5)final方法
使用final方法的原因有两个:第一是把方法锁定,以防止任何继承类修改它的含义。确保在继承中使方法行为保持不变,并且不会被覆盖。
第二是早期处理效率问题,但在java SE5/6后,应该让编译器和JVM去处理效率问题,只有在想要明确禁止覆盖时,才将方法设置为final的。

(6)final和private关键字:类中所有private方法都隐式地指定为final的。可以对private方法添加final修饰词,但这并不能给该方法增加任何额外的意义。

(7)fianl类
当将某个类的整体定义为final时,就表明了你不打算继承该类,而且也不允许别人这样做。final类中所有的方法都隐式指定为是final的。

9.初始化及类的加载

public 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 MainJava extends Insect{ 
	 private int k = printInit("MainJava.k initialized"); //第五个执行
	 public MainJava(){ 
		 //第六个执行
		 System.out.println("k="+k);
		 System.out.println("j="+j);
	 }
	 private static int x2 = printInit("static MainJava.x2 initialized");//第二个执行
	 public static void main(String[] args) { 
		 System.out.println("MainJava constructor"); //第三个执行
		 MainJava b = new MainJava();  //先调用基类的构造方法
	}

}

基类构造器和导出类的构造器一样,以相同的顺序来经历相同的过程。在基类构造器完成之后,实例变量按次序被初始化。最后,构造器的其余部分被执行。

猜你喜欢

转载自blog.csdn.net/weixin_42763504/article/details/86665845