建议4: 避免带有变长参数的方法重载

在项目和系统的开发中,为了提高方法的灵活度和可复用性,我们经常要传递不确定数量的参数到方法中,在Java 5之前常用的设计技巧就是把形参定义成Collection类型或其子类类型,或者是数组类型,这种方法的缺点就是需要对空参数进行判断和筛选,比如实参为null值和长度为0的Collection或数组。

而 Java 5引入变长参数(varags)就是为了更好地提高方法的复用性,让方法的调用者可以“随心所欲”地传递实参数量,当然变长参数也是要遵循一定规则的,

比如变长参数必须是方法中的最后一个参数;一个方法不能定义多个变长参数等,这些基本规则需要牢记,但是即使记住了这些规则,仍然有可能出现错误,我们来看如下代码:

 public class Client {
//简单折扣计算
public void calPrice(int price,int discount){
float knockdownPrice =price * discount / 100.0F;
System.out.println("简单折扣后的价格是:"+formateCurrency(knockdownPrice));
}
//复杂多折扣计算
public void calPrice(int price,int... discounts){
float knockdownPrice = price;
for(int discount:discounts){
knockdownPriceknockdownPrice = knockdownPrice * discount / 100;
}
System.out.println("复杂折扣后的价格是:" +formateCurrency(knockdownPrice));
}
//格式化成本的货币形式
private String formateCurrency(float price){
return NumberFormat.getCurrencyInstance().format(price/100);
} public static void main(String[] args) {
Client client = new Client();
//499元的货物,打75折
client.calPrice(49900, 75);
}
}

运行结果:

简单折扣后的价格是:¥374.25

这是一个计算商品价格折扣的模拟类,带有变长参数的calPrice方法则是较复杂的折扣计算方式,多种折扣的叠加运算(模拟类是一种比较简单的实现)在实际生活中也是经常见到的,比如在大甩卖期间对VIP会员再度进行打折;或者当天是你的生日,再给你打个9折,也就是俗话说的“折上折”。

两个calPrice()方法重载有点特殊:calPrice(int price,int... discounts)的参数范畴覆盖了calPrice(int price,int discount)的参数范畴。那问题就出来了:对于calPrice(49900,75)这样的计算,到底该调用哪个方法来处理呢?

从运行结果来看是调用了第一个方法,而不是变长参数的方法.

因为Java在编译时,首先会根据实参的数量和类型(这里是2个实参,都为int类型,注意没有转成int数组)来进行处理,也就是查找到calPrice(int price,int discount)方法,而且确认它是否符合方法签名条件。现在的问题是编译器为什么会首先根据2个int类型的实参而不是1个int类型、1个int数组类型的实参来查找方法呢?这是个好问题,也非常好回答:因为int是一个原生数据类型,而数组本身是一个对象,编译器想要“偷懒”,于是它会从最简单的开始“猜想”,只要符合编译条件的即可通过,于是就出现了此问题。

问题是阐述清楚了,为了让我们的程序能被“人类”看懂,还是慎重考虑变长参数的方法重载吧,否则让人伤脑筋不说,说不定哪天就陷入这类小陷阱里了。

//============================================

这里说一个Java编译器的"最短路径原则":如果能够在本类中查找到的变量,常量,方法,就不会到其他包或父类,接口中查找,以确保本类中的属性方法优先.

[改善Java代码]避免带有变长参数的方法重载的更多相关文章

  1. [改善Java代码]覆写变长方法也循规蹈矩

    建议6:覆写变长方法也循规蹈矩 在Java中,子类覆写父类中的方法很常见,这样做既可以修正Bug也可以提供扩展的业务功能支持,同时还符合开闭原则(Open-Closed Principle),我们来看 ...

  2. Java中可变长参数的方法

    原文转自:http://www.cnblogs.com/lanxuezaipiao/p/3190673.html 在Java5 中提供了变长参数(varargs),也就是在方法定义中可以使用个数不确定 ...

  3. Java Filter过滤xss注入非法参数的方法

    http://blog.csdn.NET/feng_an_qi/article/details/45666813 Java Filter过滤xss注入非法参数的方法 web.xml: <filt ...

  4. JavaSE 可变参数的方法重载

    /** * 可变参数的方法重载 */ class A { public void test(int a, int b) { System.out.println(a+", "+b) ...

  5. [改善Java代码]避开基本类型数组转换列表陷阱

    开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...

  6. [改善Java代码]强制声明泛型的实际类型

    Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. import java.util.Ar ...

  7. [改善Java代码]asList方法产生的List对象不可更改

    上一个建议之处了asList方法在转换基本类型数组时候存在的问题,在看下asList方法返回的列表有何特殊的地方.看代码: import java.util.Arrays; import java.u ...

  8. [改善Java代码]动态加载不适合数组

    上一个建议解释了为什么要使用forName,本建议就说说哪些地方不适合使用动态加载. 如果forName要加载一个类,那它必须是一个类------8中基本类型就排除在外.它们不是一个具体的类. 其次它 ...

  9. [改善Java代码]Java的泛型是类型擦除的

    泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...

随机推荐

  1. 【转】新建maven工程为什么jdk会是默认版本 而不是自己设置的版本?

    原文链接:为什么我eclipse新建项目的时候默认的是JRE1.5? 修改Maven中conf目录里的setting.xml文件内容,加上如下内容: <profiles> <!-- ...

  2. Codeforces Round #337 (Div. 2) D. Vika and Segments (线段树+扫描线+离散化)

    题目链接:http://codeforces.com/contest/610/problem/D 就是给你宽度为1的n个线段,然你求总共有多少单位的长度. 相当于用线段树求面积并,只不过宽为1,注意y ...

  3. POJ 1679 The Unique MST (次小生成树)

    题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...

  4. MFC通过对话框窗口句柄获得对话框对象指针

       C***Dialog* pWnd= (C***Dialog*)FromHandle(hWnd); //由句柄得到对话框的对象指针    pWnd->xxx( );              ...

  5. 网络子系统53_ip协议分片重组_内存阈值

    //调用路径:ip_defrag->ip_evictor // 分片重组时,可使用内存上下限: // 1.sysctl_ipfrag_high_thresh 可用内存上限 // 2.sysctl ...

  6. 转载“启动\关闭Oracle数据库的多种方法”--来自百度#Oracle

    启动\关闭Oracle数据库的多种方法 启动和关闭oracle有很多种方法. 这里只给出3种方法: l         Sql*plus l         OEM控制台 l         Wind ...

  7. 再次理解JavaScript原型链和匿名函数

    <!--------------------------------------------- 1.演示匿名加载 2.js单进程执行流 3.原型链理解 a.__proto__:属性每个对象都有 ...

  8. Spring和Hibernate集成的HibernateTemplate的一些常用方法总结

    1:get/load存取单条数据 public Teacher getTeacherById(Long id) { return (Teacher)this.hibernateTemplate.get ...

  9. Java:浅谈InputStream的close方法

    原则:最好在任何时候使用InputStream或者OutputStream的时候,在finally中调用close()方法,显式关闭. 一个典型的示例 InputStream in = null; t ...

  10. 序列化对象C++对象的JSON序列化与反序列化探索

    新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正 一:背景 作为一名C++开发人员,我始终很期待能够像C#与JAVA那样,可以省力的进行对象的序列化与反序列化,但到现在为止,还没有找 ...