复用代码是Java众多引人注目的功能之一,但要想成为机具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情。Java是面向对象的一门语言,以类为单元构建,所以复用的窍门在于使用类而不破坏现有的代码,一般有两种方法:组合和继承。
1.组合(has—a)
组合只需在新类中产生现有类的对象。由于新的类是由现有类的对象所组成,该方法只是复用了现有程序代码的功能,而非它的形式。
比如说我们写的一个类,需要一些String类型的变量来保存名字、属性等等,就可以直接在类中声明一个String类型,这就是组合,也是我们平常用的很多的方式。创建了String对象之后,就可以调用一些方法对其进行操作了。
2.继承(is—a)
继承是所有面向对象语言必不可少的组成部分。在Java中,我们强调一切都是对象,所以当你创建了一个新类时,默认都继承了Object类,这是Java所有类的根类,这也比较符合Java的逻辑。
在继承过程中,需要先声明“新类与旧类相似”。这种声明是通过在创建类时在类名后添加关键字extends以及父类的名称而实现的。当这么做时,会自动得到父类中的所有域和方法。
比如说:有一个父类Student
public class Student {
private String name;
protected int age;
public int grade;
public String subject() {
return "Student subject";
}
}
subject方法返回学生的所学课程,这时再创建子类Undergraduate(大学生)
public class Undergraduate extends Student {
public static void main(String[] args) {
Undergraduate undergraduate = new Undergraduate();
undergraduate.age=22;
undergraduate.grade=18;
System.out.println(undergraduate.subject());
}
}
结果为:Student subject
注意到尽管子类中没有声明age和grade域,但因为父类中有并且访问权限分别为protected和public,所以在子类中是可以调用的,同样,子类中并没有声明任何方法,但是依旧可以调用从父类中继承的subject方法。
接下来,在子类中添加如下方法
@Override
public String subject() {
// TODO Auto-generated method stub
return "微积分";
}
由于继承,子类中已经有了这样一个方法,所以现在重写了这个方法,也就是覆盖,再执行上面的代码,结果为
微积分
至于有关子类初始化的一些问题,我会另外写篇博客详细讲解有关继承语法中的初始化问题。
3.向上转型
由于继承可以确保基类中所有的方法在导出类中也同样有效,所以能够向基类发送的所有信息同样也可以向导出类发送。
由于继承,对象既可以作为它自己本身的类型使用买也可以作为它的基类型使用。把对某个对象的引用视为对其基类型的引用的做法称为向上转型。
因此我们可以写如下的语句:Student student=new Undergraduate();赋值语句的意义是右值是左值,这里也就是说大学生是学生,这是符合逻辑的。所以向上转型总是安全的,但由于引用为Student类型,所以发生了接口窄化,也就是该对象现在只可以调用Student中的方法,而不能调用Undergraduate
中新增的方法。
4.总结
复用类一般有两种方法,组合使我们最常使用的;继承要明白导出类是基类的超集,基类是导出类的子集;向上转型是安全的,但是发生了接口窄化。