zoukankan      html  css  js  c++  java
  • Effective_java之二:慎用重载函数

    每周写一篇技术博客的愿望一直没实现, 从这周開始每周五晚10点是写博客的时间


    OOP的一个重要特性就是多态,实现多态的目的有多种途径。比方:重载overload、重写overwite、面向接口编程等等。可是在实际应用中应该慎用重载,这也是Effective Java中提到的一条。以下先展示下eJava中提到的代码:

    @Test
    public void testOverWrite(){
    List<Integer> intList = new ArrayList<Integer>();
    Set<Integer> intSet = new HashSet<Integer>();

    for(int i = -3 ; i < 3 ; i++){
    intList.add(i);
    intSet.add(i);
    }
    System.out.println(intList+" ---> "+intSet);

    for(int i =0 ; i< 3 ;i++){
    intList.remove(i);
    intSet.remove(i);
    }

    System.out.println(intList+" ### "+intSet);

    }

    假设没有test的话可能非常多人会以为输出这样吧:

    [-3, -2, -1, 0, 1, 2]  --->  [0, 1, 2, -3, -2, -1]
    [-3, -2, -1] ###  [-3, -2, -1]

    可是结果却是这种:

    [-3, -2, -1, 0, 1, 2]  --->  [0, 1, 2, -3, -2, -1]
    [-2, 0, 2]  ###  [-3, -2, -1]

    第一行肯定都没问题,intSet也没问题。intList可能非常多人会有疑问了‘’为什么跟intSet不一样了‘

    事实上在JDK5之前也没这问题,jdk5及以后添加了自己主动封装箱的功能,基本类型和对引用类型会自己主动帮你转换。

    这样就导致了List在remove的时候移除的是索引,而不是你以为的容器内的数据。

        public E remove(int index) {
            rangeCheck(index);


            modCount++;
            E oldValue = elementData(index);


            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // Let gc do its work


            return oldValue;
        }

    而非这个函数:

    public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }

    jdk自己主动帮你解装箱了。而HashSet没有remove索引的方法所以调用了是remove对象

      public boolean remove(Object o) {
            return map.remove(o)==PRESENT;
        }

    因此不会出现list那种问题。

    所以当List remove一个Integer对象的时候须要注意,非常可能结果不是你想要的功能。

    -------------------------美丽的切割线——————————————————

    二、当參数列表类似时,最好不要用重载。特别是导出公共的API。最easy是 使用者 造成困惑。如我今天遇到的一公共Money类中有两个參数列表同样的函数:multiply和multiplyBy,拥有同样的參数列表。首次使用时跟进去细致开了代码,记住了multiply内部是新new了个对象,原来对象的值不变。也理解了这个值是不能改变的。可是这次上线前优化了行代码,使用了’multiply‘.測试时仅仅跟进了上半部分,发现数据是对的。结果最后又问题了,最后发现使用了是multiplyBy,而该函数是改变原来对象的。浪费了一时间。为什么不写全称呢?一个函数名大概最多能够用65535个字符长度,貌似再复杂的业务函数名也用不了这么长吧。


    ————————华丽的切割线————————————————-———

    三、观察代码:

    private static void printClassName(Set<?> set){
    System.out.println(set.getClass().getSimpleName());
    }
    private static void printClassName(List<?> list){
    System.out.println(list.getClass().getSimpleName());
    }
    private static void printClassName(Collection<?> col){
    System.out.println("unknow class name...");
    }
    public static void main(String[] args) {
    String[] str = {"a","b"};
    Collection<Integer>[] cols = {
    new HashSet<Integer>(),
    new ArrayList<Integer>(),
    new HashMap<Integer,Integer>()
    };
    for(Collection col : cols){
    printClassName(col)
    }
    }

    overwiter是在父子类间实现,overload是在同一个类中实现。所以overload是编译期决定的。依据引用的类型决定调用哪个方法。所以上述三次都会打印’unknow class name‘.由于编译器col都是collection类型的。

    而overload是依据执行时被调用方法所在类实例的类型选择方法的, 所以会使用子类中被复写的实现。







  • 相关阅读:
    POJ 2723 Get Luffy Out(2-SAT)
    ZOJ 3613 Wormhole Transport
    HDU 4085 Peach Blossom Spring
    NBUT 1221 Intermediary
    NBUT 1223 Friends number
    NBUT 1220 SPY
    NBUT 1218 You are my brother
    PAT 1131. Subway Map (30)
    ZSTU OJ 4273 玩具
    ZSTU OJ 4272 最佳淘汰算法
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4003846.html
Copyright © 2011-2022 走看看