慎用重载

下面这个程序的意图是好的,它试图根据一个集合是set,list,还是其他集合类型,来进行分类:

public class CollectionClassifier {
    public static String classify(Set s) {
        return "Set";
    }
 
    public static String classify(List lst) {
        return "List";
    }
 
    public static String classify(Collection c) {
        return "Unknown Collection";
    }
 
    public static void main(String[] args) {
        Collection[] collections = {
            new HashSet(),
            new ArrayList(),
            new HashMap().values()
        };
 
        for (Collection c : collections)
            System.out.println(classify(c));
    }
}

我们希望打出的是,set,list,Unknown Collection。实际上,它的输出是:

Unknown Collection
Unknown Collection
Unknown Collection

为什么会这样,因为classify放发被重载,而需要调用哪个重载放发是在编译时候做出决定的,对于for循环中的全部三次迭代,参数的编译时类型都是相同的:Collection.,每次迭代的运行时类型都是不同的,但这并不影响对重载方法的选择。
这个程序的行为有悖常理,因为对于重载方法的选择是静态的,而对于被覆盖的方法的选择是动态的,选择被覆盖的方法的正确版本是在运行时进行的,选择的依据是被调用方法所在对象的运行时类型,举个例子

class Wine {
    String name() { return "wine"; }
}
 
class SparklingWine extends Wine {
    @Override String name() { return "sparkling wine"; }
}
 
class Champagne extends SparklingWine {
    @Override String name() { return "champagne"; }
}
 
public class Overriding {
    public static void main(String[] args) {
        Wine[] wines = {
            new Wine(), new SparklingWine(), new Champagne()
        };
        for (Wine wine : wines)
            System.out.println(wine.name());
    }
}

使用重载的原则

  • 永远不要导出两个具有相同参数数目的重载方法。尽量使重载方法的参数数量不同;对于使用的可变参数,最好不要重载。
  • 如果一定要重载,那么对于一对重载方法,至少要有一个对应的参数在两个重载方法中的类型“完全不同”。这样一来,就不可以把一种实例转换为另一种实例,相对来说是保守安全的。

针对上面第2条,给出一个典型的错误例子:

public class SetList {
    public static void main(String[] args) {
        Set set = new TreeSet();
        List list = new ArrayList();
 
        for (int i = -3; i < 3; i++) {
            set.add(i);
            list.add(i);
        }
 
        for (int i = 0; i < 3; i++) {
            set.remove(i);
            list.remove(i);
        }
 
        System.out.println(set + " " + list);
    }
}
[-3, -2, -1] [-2, 0, 2]

set集合和预期一致,但是list和预期不一致。对于List,有两个重载函数,这里直接重载了list.remove(i),并没有重载到list.remove(E) 纠正如下:

        for (int i = 0; i < 3; i++) {
            set.remove(i);
            list.remove(Integer.valueOf(i));
        }

你可能感兴趣的:(慎用重载)