• 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是依据执行时被调用方法所在类实例的类型选择方法的, 所以会使用子类中被复写的实现。







  • 相关阅读:
    [转] DBus学习(一):总体介绍
    [转] DBus学习(四):基础小例子(同步和异步)
    linux系统调用列表
    Quantum Espresso + Phonopy 计算声子过程
    Compile Quantum Espresso (QE)
    Ubuntu 14.04 下创建 svn repository
    Python import 模块导入问题
    修改Ubuntu下ssh登陆时的欢迎信息
    ORNL cadesvirtues上编译 RMG/ Compile RMG on Cadesvirtues at ORNL
    launch images source启动图删除后上下有黑边
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4003846.html
Copyright © 2020-2023  润新知