组合和继承是Java中实现系统功能的重用和代码的复用的两种方式。两者在实现和使用上存在一些区别:
区别1、在类之间的关系上,继承强调的是is-a的关系,即子类是父类的一种,例如:人和动物,人是动物的一种,那么人和动物之间就存在继承的关系,人为子类,动物为父类。而组合强调的是have-a的关系,即类内部被使用的那个类是该类所拥有的东西,例如:人和心脏,心脏为人所拥有的东西,那么人和心脏之间就存在组合的关系,在人这一个类的内部可以定义一个心脏类型的变量。
区别2、子类继承父类后,父类的所有属性和方法都可以被子类访问和调用,并且子类可以根据自己的需求重写父类方法的实现细节,也就是说,父类方法的实现细节对子类是可见的,所以继承又被称为“白盒复用“。而将部分类组合使用成整体类时,只要求建立一个好的接口,整体类和部分类之间不会关心各自的实现细节,所以被称为“黑盒复用”。因为子类能拥有和改写父类中的属性和方法,所以组合在封装性上要优于继承。同时,由于继承中子类和父类的耦合度较高,使子类缺乏一定的独立性,并在父类代码进行修改时,子类也不得不进行相应的修改,增加了维护的难度。
区别3、继承是在编译时刻静态定义的,即是静态复用,在编译后子类和父类的关系就已经确定了。而组合是运用于复杂的设计,它们之间的关系是在运行时候才确定的,即在对象没有创建运行前,整体类是不会知道自己将持有特定接口下的哪个实现类。因此,在扩展方面组合比继承更具有广泛性,同时也能使每个类更专注于自身的功能,但组合的使用会使得在程序运行的过程中创建许多对象。