文章目录
前言
一、避免带有可变参数的方法重载
1.可变参数与非可变参数的方法重载
示例:
思考:
结果:
2.可变参数与可变参数的方法重载
示例:
思考:
结果:
二、带有可变参数的方法重写
1.方法重写
示例:
思考:
结果:
总结
参考文献
前言
在项目和系统的开发中,为了提高代码的灵活性和可复用性,我们经常要传递不确定量的参数到方法中,可变参数(varags)的引人实现了这一需求。当然可变参数也是要遵循一定规则的,比如可变参数必须是方法的最后一个参数;一个方法不能定义多个可变参数等。这些基本规则需要牢记,但及时记住了这些规则,仍然有可能出现错误。
本文将介绍可变参数的部分使用技巧。
一、避免带有可变参数的方法重载
1.可变参数与非可变参数的方法重载
示例:
public class VaragsDemo {
public void sale(Double price){
Double discountedPrice = price * 0.9;
System.out.println("单间商品折后价格" + discountedPrice);
}
public void sale(Double...prices){
Double sumPrice = 0.0;
for (Double price : prices) {
sumPrice += price;
}
Double discountedPrice = sumPrice * 0.8;
System.out.println("多件商品折后价格" + discountedPrice);
}
}
示例中定义了用于计算折后商品价格的方法sale()。根据买的商品数量不同,所打的折扣也不同。单件商品打9折,而多件商品则打8折。其中两个方法“方法名相同,参数类型或数量不同”,符合方法重载的定义。
思考:
执行以下代码的结果会是如何?
public class Test {
public static void main(String[] args) {
VaragsDemo varagsDemo = new VaragsDemo();
//买了一件90元的商品
varagsDemo.sale(90.0);
}
}
这里我们希望调用单件商品的折扣方法,但仔细想一下,这次的方法重载似乎有些特殊。方法sale(Double...prices)参数范围覆盖了sale(Double price),即这里调用两个方法的哪一个都有可能,这大大降低了代码的可读性,且容易出错。
结果:
单间商品折后价格81.0
从结果可以看出,代码确实按照我们的预想完成了单件商品的折扣计算。这是因为Java在编译时,首先会根据实参的数量和类型进行处理,这里的90.0被当做Double类进行了装箱,而非被当做一个Double数组,因此调用了sale(Double price)方法。而之所以没有被当做数组,是因为编译器会从最简单的开始“猜想”,只要符合编译条件即可通过。
虽然代码的运行与我们的需求相同,但这里考虑到代码的可读性等问题,依然不建议对带有可变参数的方法进行重载。
2.可变参数与可变参数的方法重载
示例:
public class VaragsDemo {
public void methodA(String str,Integer...i){}
public void methodA(String str,String...strs){}
}
在示例中对两个methodA()方法进行了重载,接下来看看他们的编译情况。
思考:
以下代码是否可以通过编译?
public class Test {
public static void main(String[] args) {
VaragsDemo varagsDemo = new VaragsDemo();
varagsDemo.methodA("hello",1998);
varagsDemo.methodA("hello","world");
varagsDemo.methodA("hello");
varagsDemo.methodA("hello",null);
}
}
这里根据不同的参数类型对methodA()方法进行了四次调用,按理说四种参数都能找到对应的方法签名(Method Signature),那么是否全部可以通过编译呢?
结果:
其中varagsDemo.methodA("hello")和varagsDemo.methodA("hello",null)编译报错。
对于varagsDemo.methodA("hello"),由于两个方法都符合形参格式,编译器不知道该调用哪个方法,因此报错。要知道可变参数的数量可以是0个,而一个符合规范的方法居然出错了,这显然是不应该出现的。因此不建议对带有可变参数的方法进行重载。
而对于varagsDemo.methodA("hello",null),直接量null是没有类型的,因此两个方法都符合形参格式,编译器不知道该调用哪个方法,因此报错。可以修改为如下形式,声明null的类型,这不仅可以通过编译,也有助于代码的理解。
public class Test {
public static void main(String[] args) {
VaragsDemo varagsDemo = new VaragsDemo();
String strs = null;
varagsDemo.methodA("hello",strs);
}
}
二、带有可变参数的方法重写
1.方法重写
示例:
public class Base {
public void demo(String...strs){
System.out.println("Base类的Demo方法");
}
}
public class Sub extends Base{
@Override
public void demo(String[] strs){
System.out.println("Sub类的Demo方法");
}
}
在示例中定义父类Base类和子类Sub类,在子类中对demo()方法完成了重写。我们知道重写方法时,参数列表必须与被重写方法相同,那么在此处@Override注解是否会报错呢?其实父类的demo()方法编译成字节码后的形参是一个String类型的数组,这和子类的参数列表相同,因此这里的重写符合规范,@Override注解没有问题。
思考:
以下代码是否能通过编译?
public class Test {
public static void main(String[] args) {
Base base = new Sub();
base.demo("Hello");
Sub sub = new Sub();
sub.demo("Hello");
}
}
这里分别通过多态形式和普通形式创建了两个Sub类的对象,分别调用demo()方法,是否都可以通过编译并执行呢?
结果:
其中base.demo("Hello")可以通过编译,并正常执行。这是由于可变参数在编译时,将String类型的"Hello"编译成了String数组,再由子类Sub完成执行。
而直接用子类调用的sub.demo("Hello")则不能通过编译,这是因为编译器没有把String类型的"Hello"编译成String数组,参数类型不匹配,编译器自然会拒绝。
同样的方法名,同样的参数,通过父类可以调用,而通过子类则不能调用。重写方法的参数列表居然与父类不同,这违背了重写的定义。因此在对带有可变参数的方法进行重写时,需注意参数的形式。
总结
本文主要总结了几条可变参数的使用技巧。
1.不要对带有可变参数的方法进行重载。
2.重写可变参数的方法时,要注意参数形式。
参考文献
[1]秦小波.编写高质量代码[M]:机械工业出版社
示例:
public class VaragsDemo {
public void sale(Double price){
Double discountedPrice = price * 0.9;
System.out.println("单间商品折后价格" + discountedPrice);
}
public void sale(Double...prices){
Double sumPrice = 0.0;
for (Double price : prices) {
sumPrice += price;
}
Double discountedPrice = sumPrice * 0.8;
System.out.println("多件商品折后价格" + discountedPrice);
}
}
单间商品折后价格81.0
public class VaragsDemo {
public void methodA(String str,Integer...i){}
public void methodA(String str,String...strs){}
}



