继承与组合
继承是实现类重用的重要手段,但继承带来一个最大的坏处:破坏封装。组合也是实现类重用的重要方式,而采用组合方式来实现类重用则能提供更好的封装性。
使用继承的注意点
子类扩展父类时,子类可以从父类继承得到Field和方法,如果访问权限允许,子类可以直接访问父类的Field和方法,相当于子类可以直接复用父类的Field和方法。
封装:每个类都应该封装它内部信息和实现细节,而只暴露必要的方法给其他类使用。
为了保证父类的封装性,设计父类应该遵循如下规则:
》尽量隐藏父类的内部数据,尽量把父类的所有Field都设置成private访问类型,不要让子类直接访问父类的Field。
.》不要让子类可以随意访问,修改父类的方法。父类中那些仅为辅助其他的工具方法,应该使用private修饰;如果父类中的方法需要被外部类调用,则必须以public修饰,但又不希望子类重写该方法,使用final修饰;如果希望父类的某个方法被子类重写,但不希望其他类自由访问,则使用protected修饰。
》尽量不要在父类构造器中来调用将要被子类重写的方法。
class Base
{
public Base()
{
test();
}
public void test()
{
System.out.println("将被子类重写的方法");
}
}
public class Sub extends Base
{
private String name;
public void test()
{
System.out.println("子类重写父类的方法,"+"其name字符串的长度"+name.length());
}
public static void main(String[]args)
{
//下面代码会引发空指针异常
Sub s= new Sub();
}
}
当系统识图创建Sub对象时,同样会先执行其父类构造器如果父类构造器调用了被其子类重写的方法,则变成调用被子类重写后的方法。当创建Sub对象时,会先执行Base类中的Base构造器,而Base构造器中调用了test方法——并不是调用父类的test方法,而是调用的i之类的test方法,此时Sub对象的nameField是null,因此空指针异常。
如果想把某些类设置成最终类,即不能被当成父类,则可以使用final修饰;使用private修饰这个类的所有构造器,从而保证子类无法调用该类的构造器,也就无法继承该类。使用private修饰的父类,可以另外提供一个静态方法,用于创建该类的实例。
什么情况下需要从父类派生新的子类呢?
》子类需要额外增加属性,而不仅仅是属性值的改变。
》子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)。
利用组合实现复用
如果需要复用一个类,出了继承外,还可以把该类当成另一个类的组合成分,从而允许新类直接复用该类的public方法。组合是把旧类对象作为新类的Field嵌入,用以实现新类的功能,用户看到的是新类的方法,而不能看到被起嵌入对象的方法。
何时使用继承?组合?
将一个较为抽象的类改变成能使用与某些特定需求的类使用继承。如果两个类之间有明确的整体,部分的关系,使用组合。