Java基础 -- 复用类(组合和继承)
复用类有两种实现方式。
- 在新的类中产生现有类的对象,由于新的类是由现有类的对象所组成,所以这种方法称之为组合。
- 采用继承实现。
一 组合语法
下面创建两个类WaterSource和SprinklerSystem。其中SprinklerSystem中包含WaterSource的对象引用。
class WaterSource { //如果定义时没有初始化,则基本类型会被自动初始化为0,对象引用初始化为Null private String s; WaterSource(){ System.out.println("WaterSource()"); s = "Constructed"; } } public class SprinklerSystem { private String value1,value2,value3,value4; //定义时初始化 private WaterSource source = new WaterSource(); private int i; private float f; public String toString() { return "value1 = " + value1 + " " + "value2 = " + value2 + " " + "value3 = " + value3 + " " + "value4 = " + value4 + "\n" + "i = " + i + " " + "f = " + f + " " + "source = " + source; } public static void main(String[] args) { SprinklerSystem sprinklers = new SprinklerSystem(); System.out.println(sprinklers); } }
运行结果如下:
WaterSource() value1 = null value2 = null value3 = null value4 = null i = 0 f = 0.0 source = WaterSource@15db9742
注意:如果把一个对象以String类型输出,则默认调用的是该对象的toString()方法。
类中成员变量如果是基本基本类型则默认被初始化为零,如果是对象引用则会被初始化为null。
我们也可以自己去初始化他们:
- 在定义成员变量的时候初始化,比如private String s1 = "happy";这意味着他们能够在构造函数被调用之前初始化。
- 在类的构造函数中初始化;
- 在使用这些成员变量之前初始化,这种方式称之为惰性初始化;
- 使用实例初始化{s1 = "happy";}。
二 继承语法
Java创建一个类时,默认都是继承于Object,除非自己指定从哪个类继承。
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) { 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); } }
运行结果如下:
Cleanser dilute() apply() Detergent.scrub() scrub() foam() Testing base class: Cleanser dilute() apply() scrub()
看以看到继承使用的是关键字extends,如果在子类中想调用父类方法,可以使用super.*。
1、初始化父类
在创建一个子类对象时,父类构造器总会在子类构造器之前被调用。
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(); } }
运行输出如下:
Art constructor Drawing constructor Cartoon constructor
所以很容易发现,子类对象的构建过程是从父类"向外"扩散的,所以父类在子类构造器可以访问它之前,就已经完成了初始化。
上面的父类构造函数是没有参数的,如果父类只有一个带有参数的构造器,就必须在子类构造器中用关键字super显式的编写调用父类构造器的语句,否则编译器将无法找到符合'类名()'形式的构造器。
2、重载
重载是指不同的函数使用相同的函数名,但是函数的参数个数和类型不同。调用的时候根据函数的参数来区别不同的函数。在Java中,子类可以重载父类的方法。
//重载显示 class Homer{ char doh(char c) { System.out.println("doh(char)"); return 'd'; } float doh(float f) { System.out.println("doh(float)"); return 1.0f; } } class Milhouse{} class Bart extends Homer{ void doh(Milhouse m) { System.out.println("doh(Milhouse)"); } } public class Overload { 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)
3、protected
在实际的项目中,经常会想要将某些事物尽可能对整个世界隐藏起来,但仍然允许子类的成员访问它们。关键字protected就起这个作用,它指明"就用户而言,这是private的,但对于任何继承于此类的子类,它是可以访问的“。
//Protected关键字的使用 class Villain{ private String name; protected void set(String nm) {name = nm;} public Villain(String name) {this.name = name;} public String toString() { return "I'm a Villain and my name is " + name; } } public class Orc extends Villain{ private int orcNumber; public Orc(String name,int orcNumber) { super(name); this.orcNumber = orcNumber; } public void change(String name,int orcNumber) { set(name); this.orcNumber = orcNumber; } public String toString() { return "Orc " + orcNumber + ": " + super.toString(); } public static void main(String[] args) { Orc orc = new Orc("Z3",12); System.out.println(orc); orc.change("l4", 23); System.out.println(orc); } }
运行结果如下:
Orc 12: I'm a Villain and my name is Z3 Orc 23: I'm a Villain and my name is l4
可以发现子类change()方法可以访问父类的set(),这是因为set()的访问修饰符是protected。
参考文献:
[1]Java编程思想