组合语法
我们看一个例子:
class WaterSource {
private String s;
WaterSource() {
System.out.println("WaterSource()");
s = "Constructed";
}
public String toString() {
return s;
}
}
public class SprinklerSystem {
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) {
SprinklerSystem sprinklers = new SprinklerSystem();
System.out.println(sprinklers);
}
}
在这段代码中,我们可以看到,每一个非基本类型的对象都有一个toString()
方法,并且当编译器需要一个String
,而你只有一个对象时,该方法就会被调用。
System.out.println()
;中需要的是一个String
,但是你只有一个对象,并且这个对象有一个toString()
方法,该方法会被调用。
再进一步的,"source = " + source
中,source是一个对象,由于只能将一个String对象和String对象进行相加,所以,source中的toString()
将会被调用。
继承语法
继承是为了使用一个已经存在的类的定义作为基础,新类的定义可以添加新的数据和新的方法,也可以用父类的功能。继承可以很容易复用的代码。继承是为了重用父类代码,同时为实现多态性做准备(待理解)。
我们看一个例子:
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 {
//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();
System.out.println(x);
//test the bas class
System.out.println("Test the base class");
CLeanser.main(args);
}
}
1、使用了 += 重载操作符
2、每一个类中都有main方法(单元测试)
3、只有命令行调用的那个类的main方法才会被调用
4、即使一个类不是public类,如果命令行是java Cleanser,那么Cleanser.main(),任然可以被调用。即使一个类中只有包的访问权限,其public main也是可以访问的。
5、在这个例子中,Detergent.main 明确调用了CLeanser.main,并且从命令行获取参数传递给CLeanser.main,当然也可以传递任意String数组。
6、Cleanser中的所有方法都必须是public的,这一点很重要。如果没有任何访问权限修饰,那么成员默认的访问权限是包访问权限,仅仅允许包内成员访问。但是包中的都一个类要从Cleanser中继承,则只能访问public成员。所以,为了继承,一般的规则就是将所有的数据成员指定为private,所有的方法指定为public。
7、在Cleanser接口中的一组方法:append(), dilute(), apply(), scruc()和toString()。由于Detergent是通过关键字extends从Cleanser中导出的,所以它可以其接口中自动获取这些方法,尽管并不能真正看到这些方法在Detergent中的显式定义。因此,继承视作为对类的复用。
8、在scrub()中可见,使用基类中定义的方法及对他进行修改是可行的。在此例中,你可能想要在新版本中调用从基类继承而来的方法。但是在scrub中并不能直接调用scrub,这样会产生递归。因此,Java中通过super关键字表示超类,就是当前类是从超类继承而来的。表达式super.scrub将调用基类版本的scrub方法。
9、在继承的过程中,并不一定非要使用基类的方法,也可以咋导出类中添加新方法。比如foam()
初始化基类
看一个例子:
class Art {
Art() {
System.out.println("Art constructor");
}
}
class Drawing extends Art {
Drawing() {
System.out.println("Drawing constructor");
}
}
public class Cartoon extends Drawing {
public Cartoon() {
System.out.println("Cartoon constructor");
}
public static void main(String[] args) {
Cartoon x = new Cartoon();
}
}
output:
Art constructor
Drawing constructor
Cartoon constructor
我们通过在构造函数中打印调试信息,来观察构造的过程。于是发现,构建过程是从基类向外扩散的。
代理
在看一个例子
例如太空船需要一个控制模块:
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 SpaceShip extends SpaceShipControls {
private String name;
public SpaceShip(String name) {
this.name = name;
}
public String toString() {
return name;
}
public static void main(String[] args) {
SpaceShip ship = new SpaceShip("GM-JIANG DE SPACESHIP");
ship.forward(100);
}
}
这里我们使用了继承的方法。更准确的说SpaceShip包含了SpaceShipControls,于此同时SpaceShipControls的所有方法在SpaceShip中都暴露出来了。
下面用代理来解决此题:
class SpaceShipControls1 {
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 SpaceShipDelegation {
private String name;
private SpaceShipControls1 controls = new SpaceShipControls1();
public SpaceShipDelegation(String name) {
this.name = name;
}
//Delegation methon
public void back(int velocity) {
controls.back(velocity);
}
public void down(int velocity) {
controls.down(velocity);
}
public static void main(String[] args) {
SpaceShipDelegation ship = new SpaceShipDelegation("GM-JIANG DE SPACESHIP");
ship.back(100);
}
}
可以看到,上面的方法是如何传递给了底层的controls对象的,而其接口由此也就与使用继承得到的接口相同了。但是,我们使用代理时可以拥有更多的控制力,因为我们可以选择只提供在成员对象中的方法的某个子集。