慎用重载。

对于重载方法(overloaded method)的选择是静态的,而对于被覆盖的方法(overridden method)的选择则是动态的。选择被覆盖的方法的正确版本是在运行时进行的,选择的依据是被调用方法所在对象的运行时类型。这里重新说明一下,当一个子类包含的方法声明与其祖先类中的方法声明具有同样的签名时,方法就被覆盖了。如果实例方法在子类中被覆盖了,并且这个方法是在该子类的实例上被调用的,那么子类中的覆盖方法(overriding method)将会执行,而不管该子类实例的编译时类型到底是什么。

到底怎样才算胡乱使用重载机制呢?这个问题仍有争议。安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法。如果方法使用可变参数(varargs),保守的策略是根本不要重载他。如果你遵守这些限制,程序员永远也不会陷入到“对于任何一组实际的参数,哪个重载方法是适用的”这样的疑问中。这项限制并不麻烦,因为你始终可以给方法起不同的名称,而不使用重载机制。

例如,考虑ObjectOutputStream类。对于每个基本类型,以及几种引用类型,他的write方法都有一种变形。这些变形方法并不是重载write方法,而是具有诸如writeBoolean(boolean)、writeInt(int)和writeLong(long)这样的签名。与重载方案比较,这种命名模式带来的好处是,有可能提供相应名称的读方法,比如readBoolean()、readInt()和readLong()。实际上,ObjectInputStream类正是提供了这样的读方法。

对于构造器,你没有选择使用不同名称的机会;一个类的多个构造器总是重载的。在许多情况下,可以选择导出静态工厂,而不是构造器。对于构造,还不用担心重载和覆盖的相互影响,因为构造器不可能被覆盖。或许你有可能导出多个具有相同参数数目的构造器,所以有必要了解一下如何安全的做到这一点。

如果对于“任何一组给定的实际参数将应用于哪个重载方法上”始终非常清楚,那么,导出多个具有相同参数数目的重载方法就不可能使程序员感到混淆。如果对于每一对重载方法,至少有一个对应的参数在两个重载方法中具有“根本不同”的类型,就属于这种情形。如果显然不可能把一种类型的实例转换为另一种类型,这两种类型就是根本不同的。在这种情况下,一组给定的实际参数应用于哪个重载方法上就完全由参数的运行时类型来决定,不可能受到其编译时类型的影响,所以主要的混淆根源就消除了。

简而言之,“能够重载方法”并不意味着就“应该重载方法”。一般情况下,对于多个具有相同参数数目的方法来说,应该尽量避免重载方法。在某些情况下,特别是涉及构造器的时候,要遵循这条建议也许是不可能的。在这种情况下,至少应该避免这样的情形:同一组参数只需经过类型转换就可以被传递给不同的重载方法。如果不能避免这种情形,例如,因为正在改造一个现有的类以实现新的接口,就应该保证:当传递同样的参数时,所有重载方法的行为必须一致。如果不能做到这一点,程序员就很难有效地使用被重载的方法或者构造器,他们就不能理解他为什么不能正常的工作。

猜你喜欢

转载自blog.csdn.net/en_joker/article/details/81001283