每周写一篇技术博客的愿望一直没实现, 从这周開始每周五晚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是依据执行时被调用方法所在类实例的类型选择方法的, 所以会使用子类中被复写的实现。

Effective_java之二:慎用重载函数的更多相关文章

  1. 【C++初学者自学笔记三】哑元函数、缺省参数、内联函数(模块二,PS:需要用到重载函数)

    一,哑元函数:一个函数的参数只有类型没有名字的则这个参数称之为哑元.类似于void fun(int); 功能:1保持向前的兼容性,比方说我们需要做成一个成品,然后成品是会不断的更新第一代第二代,当我们 ...

  2. C++学习笔记(十二):重载函数

    1. 什么是重载函数 假设同一作用域内的几个函数名字同样但形參列表不同.那么这些函数就称之为--重载函数. 比如: void print( const char *cp); void print(co ...

  3. C++ 类的多态二(函数重载--函数重写--函数重定义)

    //函数重载--函数重写--函数重定义 #include<iostream> using namespace std; /* 函数重载: 必须在一个类中进行(子类无法重载父类中的函数) 子 ...

  4. C++学习基础十二——纯虚函数与抽象类

    一.C++中纯虚函数与抽象类: 1.含有一个或多个纯虚函数的类成为抽象类,注意此处是纯虚函数,而不是虚函数. 2.如果一个子类继承抽象类,则必须实现父类中的纯虚函数,否则该类也为抽象类. 3.如果一个 ...

  5. C++:运算符重载函数之友元运算符重载

    5.2.2 友元运算符重载函数 运算符重载函数一般采用两种形式定义: 一是定义为它将要操作的类的成员函数(简称运算符重载函数): 二是定义为类的友元函数(简称为友元运算符重载函数). 1.定义友元运算 ...

  6. c++选择重载函数

    一.函数重载 普通函数重载的关键是参数列表---也称函数特征标.函数参数中有以下情况可以出现重载: 1.  形参个数不同 2.  形参的类型不同 3.  形参的类型和个数都不同 const形参和函数重 ...

  7. Spline样条函数 //C++关键字:operator // 重载函数 // 隐含的this指针 // 指针和const限定符

    在数学学科数值分析中,样条是一种特殊的函数,由多项式分段定义.样条插值是使用一种名为样条的特殊分段多项式进行插值的形式.由于样条插值可以使用低阶多项式样条实现较小的差值误差,这样就避免了使用高阶多项式 ...

  8. 动态对象创建(二)重载new和delete

    动态对象创建(二)重载new和delete 前言 上文我简单介绍了一下动态对象创建的方法,这一篇文章的内容主要是对重载new和delete做一些讲解,也希望能够得到博友们的指点,在这里谢过大家. 通常 ...

  9. 《挑战30天C++入门极限》C++中利用构造函数与无名对象简化运算符重载函数

        C++中利用构造函数与无名对象简化运算符重载函数 在完整描述思想之前,我们先看一下如下的例子,这个例子中的加运算符重载是以非成员函数的方式出现的: //程序作者:管宁  //站点:www.cn ...

随机推荐

  1. vim开发环境配置

    一.大饱眼福 看了效果图,肯定有人说, 这都有啥功能?就花哨? 告诉你,你说花哨就错了,开玩笑?我们程序猿可都是实打实的人,说谎都不会,咋会忽悠人呢. 下面我来告诉你,这都有些什么功能: 文件索引功能 ...

  2. C++二叉树的实现

    C++实现二叉查找树 啥是二叉查找树 在数据结构中,有一个奇葩的东西,说它奇葩,那是因为它重要,这就是树.而在树中,二叉树又是当中的贵族.二叉树的一个重要应用是它们在查找中的应用,于是就有了二叉查找树 ...

  3. JAVA分析html算法(JAVA网页蜘蛛算法)

    近来有些朋友在做蜘蛛算法,或者在网页上面做深度的数据挖掘.但是遇到复杂而繁琐的html页面大家都望而却步.因为很难获取到相应的数据. 最古老的办法的是尝试用正则表达式,估计那么繁琐的东西得不偿失,浪费 ...

  4. vim7.4 安装 k-vim

    注:在虚拟机 kali 1.9中安装完成之后,无法连接到网络(目前没找到有效的解决方法,不知道是不是通病,本人安装了两次,都一样),cpu占用率 70%+  ,建议安装之前,先建立快照,否则,后悔莫极 ...

  5. CodeIgniter 3.0+ 部署linux环境 session报错

    codeigniter Message: mkdir(): Invalid path Filename: drivers/Session_files_driver.php 看起来像权限问题,在默认情况 ...

  6. 获取子窗口中使用jQuery.data()设置的参数

    http://hyj1254.iteye.com/blog/643035 假设在iframe子窗口中设置了$('#mydata').data('key','hello world'); 那在包含ifr ...

  7. hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse

    生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...

  8. QCon 2013 上海 -- 互联网金融

    互联网金融应该是最近很火爆的一个领域.由于阿里小贷和余额宝的初步成功,这一块都被视为破除传统金融领域垄断的法宝.大家可能都知道,电商平台.金融和大数据是阿里集团未来的三个重要方面.而关于金融,马云最经 ...

  9. iOS 获取通讯录权限的时机

    建议将获取通讯录权限的代码放到 -(void)viewDidAppear:(BOOL)animated 或 -(void)viewWillAppear:(BOOL)animated 假如放在 view ...

  10. POJ 2395 Out of Hay(MST)

    [题目链接]http://poj.org/problem?id=2395 [解题思路]找最小生成树中权值最大的那条边输出,模板过的,出现了几个问题,开的数据不够大导致运行错误,第一次用模板,理解得不够 ...