ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【JAVA】 重用类-合成&继承

2022-03-21 10:58:21  阅读:172  来源: 互联网

标签:System JAVA void 重用 public 合成 println class out


合成(Composition)

(hasA)
进行合成只需在新类里简单地置入对象句柄即可。

//: SprinklerSystem.java
// Composition for code reuse
package c06;
class WaterSource {
	private String s;
	WaterSource() {
		System.out.println("WaterSource()");
		s = new String("Constructed");
	}
	public String toString() { return s; }
}
public class SprinklerSystem {
	private String valve1, valve2, valve3, valve4;
	WaterSource source;
	int i;
	float f;
	void print() {
		System.out.println("valve1 = " + valve1);
		System.out.println("valve2 = " + valve2);
		System.out.println("valve3 = " + valve3);
		System.out.println("valve4 = " + valve4);
		System.out.println("i = " + i);
		System.out.println("f = " + f);
		System.out.println("source = " + source);
	}
	public static void main(String[] args) {
		SprinklerSystem x = new SprinklerSystem();
		x.print();
	}
} ///:~
/* Output: 
WaterSource() 
valve1 = null 
valve2 = null 
valve3 = null 
valve4 = null 
i = 0 f = 0.0 source = Constructed 
*///:

注意toString()方法,每种非基本类型的对象都有一个toString()方法。若编译器本来希望一个String,但却获得某个对象,就会调用这个方法。所以在下面这个表达式中:

System.out.println("source = " + source) ;

编译器会发现我们试图向一个WaterSource添加一个String对象(“source =”)。这对它来说是不可接受的,因为只能将一个字串“添加”到另一个字串,所以它会说:“我要调用toString(),把source转换成字串!”经这样处理后,它就能编译两个字串,并将结果字串传递给System.out.println()。
要在自己创建的类中允许上述这种行为,只需要写一个toString()方法即可。

注意对象句柄会初始化为null,调用其方法会抛出违例

继承(inheritance)

子类继承父类(isA)
语法:访问控制符【修饰符】class 类名 extends 父类名{}
关键字:extends
例如: public class Students extends Person{}

//: Detergent.java
// Inheritance syntax & properties
class Cleanser {
	private String s = new String("Cleanser");
	public void append(String a) { s += a; }
	public void dilute() { append(" dilute()"); }
	public void apply() { append(" apply()"); }
	public void scrub() { append(" scrub()"); }
	public void print() { System.out.println(s); }
	public static void main(String[] args) {
		Cleanser x = new Cleanser();
		x.dilute(); 
		x.apply(); 
		x.scrub();
		x.print();
	}
}
public class Detergent extends Cleanser {
	// Change a method:
	public void scrub() {
		append(" Detergent.scrub()");
		super.scrub(); // Call base-class version
	}
	// Add methods to the interface:
	public void foam() { append(" foam()"); }
	// Test the new class:
	public static void main(String[] args) {
		Detergent x = new Detergent();
		x.dilute();
		x.apply();
		x.scrub();
		x.foam();
		x.print();
		System.out.println("Testing base class:");
		Cleanser.main(args);
	}
} 
/* Output: 
Cleanser dilute() apply() Detergent.scrub() scrub() foam() 
Testing base class: 
Cleanser dilute() apply() scrub()
///:~

注意
无论Cleanser还是Detergent都包含了一个main()方法。我们可为自己的每个类都创建一个main()。通常建议大家这样编写代码,使自己的测试代码能够封装到类中。即便在程序中含有数量众多的类,但对于在命令行请求的public类,只有main()才会得到调用。所以在这种情况下,当我们使用“java Detergent”的时候,调用的是Degergent.main()——即使Cleanser并非一个public类。采用这种将main()置入每个类的做法,可方便地为每个类都进行单元测试。而且在完成测试以后,毋需将main()删去;可把它保留下来,用于以后的测试。
使用Deteregent.main()调用主方法

初始化基础类

基础类(父类)和衍生类(子类)。从外部看,新类似乎与基础类拥有相同的接口,可能还包含一些额外添加的方法和字段。但继承不是简单复制基础类的接口就完了。创建衍生类的一个对象时,它在其中包含了基础类的一个“子对象”。这个子对象就象我们根据基础类本身创建了它的一个对象。从外部看,基础类的子对象已封装到衍生类的对象里了。
基础类子对象要正确地初始化,就只能在构建器中执行初始化。在衍生类的构建器中,Java会自动插入对基础类构建器的调用。见下例:

//: Cartoon.java
// Constructor calls during inheritance

class Art {
  Art() {
    System.out.println("Art constructor");
  }
}

class Drawing extends Art {
  Drawing() {
    System.out.println("Drawing constructor");
  }
}

public class Cartoon extends Drawing {
  Cartoon() {
    System.out.println("Cartoon constructor");
  }
  public static void main(String[] args) {
    Cartoon x = new Cartoon();
  }
} ///:~

output:
Art constructor
Drawing constructor
Cartoon constructor

可以看到,构建是在基础类的“外部”进行的,所以基础类会在衍生类访问它之前得到正确的初始化。
初始化子类时会首先调用父类的构造器,初始化父类

如果父类没有默认的自变量,或是想调用某个有自变量的父类的构造器,则必须明确的写出对父类的调用代码。这时,需要用super关键字以及适当的自变量列表实现。见下例:

//: Chess.java
// Inheritance, constructors and arguments

class Game {
  Game(int i) {
    System.out.println("Game constructor");
  }
}

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();
  }
} ///:~

到底选择合成还是继承

无论合成还是继承,都可以将子对象置于新类中。
如果想利用新类内部一个现有类的特性,而不想使用它的接口,通常应选择合成。也就是说,可以嵌入一个对象,能够使用它实现新类的特性。但新类的用户会看到已定义的接口,而不是嵌入对象的接口。考虑到这种效果,我们需在新类里嵌入现有类的private对象。
有些时候,我们想让类用户直接访问新类的合成。也就是说,需要将成员对象的属性变为public。成员对象会将自身隐藏起来,所以这是一种安全的做法。而且在用户知道我们准备合成一系列组件时,接口就更容易理解。
如下例:

//: Car.java
// Composition with public objects

class Engine {
  public void start() {}
  public void rev() {}
  public void stop() {}
}

class Wheel {
  public void inflate(int psi) {}
}

class Window {
  public void rollup() {}
  public void rolldown() {}
}

class Door {
  public Window window = new Window();
  public void open() {}
  public void close() {}
}

public class Car {
  public Engine engine = new Engine();
  public Wheel[] wheel = new Wheel[4];
  public Door left = new Door(),
       right = new Door(); // 2-door
  Car() {
    for(int i = 0; i < 4; i++)
      wheel[i] = new Wheel();
  }
  public static void main(String[] args) {
    Car car = new Car();
    car.left.window.rollup();
    car.wheel[0].inflate(72);
  }
} ///:~

如果选择是引用继承,则是使用一个现成的类,制造出这个类的一个特殊版本。意思就是使用一个常规用途的类,并根据特定的需求对其进行定制。只要稍微思考下就知道自己不能用一个车辆对象来合成一辆汽车——汽车并不“包含”车辆;相反,它“属于”车辆的一种类别。“属于”(is a)关系是用继承来表达的,而“包含”(has a)关系是用合成来表达的。

标签:System,JAVA,void,重用,public,合成,println,class,out
来源: https://blog.csdn.net/loyd3/article/details/106448253

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有