要想复用代码,java中有两种方式。一种只需在新类中产生现有类的对象。由于新的类是由现有类的对象组成,所以这种方法称为组合;另一种方式按照现有类的类型来创建新类,无需改变现有类的形式,采用现有类的形式在其中添加新代码,这种方式称为继承。
一、组合
假设需要某个对象,它具有很多String对象,几个基本数据类型,以及另一个类的对象。对于非基本类型的对象,必须将其引用至于新的类中,但可以直接定义基本数据类型。
从上面输出中可以看到source输出了s的值,这是因为"source =" + source , 需要一个String对象,编译器则会调用WaterSource的toString方法转换为String。或许你会觉得调用toString方法作为一个字符串都知道,但是你怎么说明组合呢?来试一下下一个例子。
在这里,Teacher类和Student类都有成员变量People使得我们可以使用People类中的方法,通过调用people 的life方法来说明了,老师和学生也是人。并且还有自己独特的任务和学习。我是第一次听到组合的概念,之前学习到过继承,发现,和继承差不多的功能啊,为什么不直接使用继承呢?先来复习下继承,然后区别下两者的不同。
二、继承
继承是java语言中不可缺少的组成部分。当创建一个类时,总是在继承,因此除非明确指出了继承了哪个类,否则就是隐式地从Object类中进行继承。而要指明是继承了哪个类,是使用extends关键字实现的。先来看书上的例子吧
为什么要先看书上的例子呢?因为发现了一个盲点,首先呢是main方法的调用,可以在另一个类中的main方法中调用另一个类的main方法,这个是我之前没有用过的。还有这里Cleanser类中的方法都是public修饰的,如果不加修饰词,默认是包访问权限,它允许同包内的成员访问。而继承的规则呢,就是将所有的数据成员指定为private,将所有的方法指定为public,如果有特殊需求需要做出调整。继承,不显示的展现出父类的方法,也可以调用。现在用继承来实现以下组合中使用的例子吧。
对比组合的代码,少了许多,输出结果也相同。那到底使用如何选择使用呢?再了解更多后会做出解释,继续看吧。
三、初始化父类(书上是基类,也就是被继承的类)
对于这块的内容,我的理解就是,新建子类对象时,会初始化父类,也就是调用了父类的构造器。分不同情景来看一下
可以从结果中看到,先访问了Art的构造器,再访问了Drawing的构造器,最后才访问了Reuse4的构造器。也就是说,在调用子类的构造器之前,总会调用父类的构造器。
可以看到,在这里,即使Face没有无参构造,也访问了父类的构造器。并且进行了初始化成员变量n。从之前的笔记里说道,一个类的加载,会先初始化成员变量再调用构造器,这里说明了加载这个类之前,先去加载了它的父类构造器。来试一下吧。
通过执行结果,可以得出当实例化一个子类对象时,先去加载它的父类,然后才会加载本类。
上面的例子中,我们都使用的是无参构造器,如果没有无参构造的父类,或者说我们需要调用一个带参数的父类构造器,怎么做呢?使用super关键字显示的去调用父类构造器的语句。
那当我们不去写super(i)呢?
就会提示我们添加,如果我们没有在子类提供一个有参构造呢?
报错了,来看下报错语句
嗯,可能有些模糊,大概意思呢,就是父类没有无参构造,你必须提供一个,或者
点击红色线条,按提示处理,是写出了一个有参构造,并调用了super(i)。
对于初始化父类的情况呢,就是这些了。
四、代理
代理呢,就是既要讲一个成员对象置于所要构造的类中(组合),与此同时,也在新类中暴露了该成员对象的所有方法(继承)。比如要造一个太空船,太空船需要一个控制模块
使用继承方式构造一个太空船
但是这里SpaceShip并不是真正的SpaceShipControls类型,而是包含了SpaceShipControls,并且SpaceShipControls中的所有方法都暴露了出来,而代理就解决了这个问题。
可以看到,对于上面的方法如何传递给controls的,而其接口也就与使用继承得到的接口相同了,但是代理多了更多的控制,因为我们可以选择只提供成员对象方法的某个子集。