前言:最近在学习可变参数的问题,许多人说可变参数就是数组,我在查了一些资料,还有向老师请教
最终结合自己的思考得出了自己的一些理解(仅供参考,若有错误还请指出)
一.向上转型与可变参数的例题
1.情况一
public class String01
{
public static void main(String[] args) {
int [] a = {1,2,3};
Father father =new Sun();
father.element(a);
}
}
class Father{
public void element(int [] args) {
System.out.println("可变参数");
}
}
class Sun extends Father{
public void element(int ... args)
{
System.out.println("数组");
}
}
如图,这是一种特殊的方法重写,即形参不相同。调用该方法时,编译阶段看左边(即父类类型),传参时是数组,父类接受也是数组所以编译通过,在运行阶段看右边(即子类类型),先在子类中找看是否有element();方法,发现存在该方法且可变参数可以接受数组(实际上是将数组的名即地址传给可变参数,那么可变参数也指向该地址,所以可以利用下标的形式去访问),执行此方法.
运行结果如下图:
数组
进程已结束,退出代码0
如果将上述传参改为可变参数,那么在编译阶段就会报错,原因是编译类型看左边(即父类类型),但父类中该方法要求传一个数组,你传的却是一个可变参数必然会报错.
2.情况二
将参数位置调换,即父类中的参数不再是数组而是可变参数,子类中也不再是可变参数,而是数组
public class String01
{
public static void main(String[] args) {
int [] a = {1,2,3};
Father father =new Sun();
father.element(1,2,3);
}
}
class Father{
public void element(int ... args) {
System.out.println("可变参数");
}
}
class Sun extends Father{
public void element(int [] args)
{
System.out.println("数组");
}
}
同理:
在编译阶段看左边(父类类型),父类中该方法是可变参数,你传的类型也是可变参数,编译通过,在运行阶段看右边(子类类型),子类中存在该方法且可以将可变参数的值传给数组(即将1,2,3依次赋给a[0],a[1],a[2]),所以执行该方法。
运行结果如图所示
数组
进程已结束,退出代码0
public class String01
{
public static void main(String[] args) {
int [] a = {1,2,3};
Father father =new Sun();
father.element(a);
}
}
class Father{
public void element(int ... args) {
System.out.println("可变参数");
}
}
class Sun extends Father{
public void element(int [] args)
{
System.out.println("数组");
}
总结:
(1)此题是我在学习可变参数和向上转型时遇到的问题,最终得到的结论是:
可变参数与数组是有区别的(根本就是两个不同的东西),而许多人说可变参数就是数组,本质上是可变参数可以接收传来的数组名,而数组名中存放的是数值的地址,所以可变参数也就指向了该数组的地址,成为了一个引用变量,可以利用和数组一样的访问方式(即下标索引)去访问数组中的元素。
public class String01
{
public static void main(String[] args) {
int [] a = {1,2,3};
System.out.println(a);
Father father =new Sun();
father.element(a);
}
}
class Father{
public void element(int [] args) {
System.out.println("可变参数");
}
}
class Sun extends Father{
public void element(int ... args)
{
System.out.println(args);
}
}
验证猜想:
[I@1b6d3586
[I@1b6d3586
进程已结束,退出代码0
由此可见
可变参数确实和数组名指向同一个地址
(2)当我们给可变参数直接传一组数时,java中为了体现一切事物皆对象的特点,这些数被存放在一段内存地址连续的空间中(封装,我们看不到),可变参数的引用指向该存储空间的首地址,这点类似于数组。
public class list_exercise {
public static void main(String[] args) {
int a[]={1,3,5};
System.out.println(a);
sum(8,5,6,7);
}
public static void sum(int ...x)
{
System.out.println(x);
int sum=0;
for(int i=0;i< x.length;i++)
{
sum+=x[i];
}
System.out.println("sum="+sum);
}
}
运行结果如图
[I@1b6d3586
[I@4554617c
sum=26
进程已结束,退出代码0
由此可见传入一组数时类似于数组,这组数被封装在一组地址连续的空间,这里为了避免输出可变参数地址与上述相同,所以先输出a的地址(地址的分配本身就具有随机性)
而上题主要是要区分:
1.编译阶段看左边,运行阶段看右边,且运行时先从子类中去找.
2.编译阶段主要看类型是否匹配(例如:int a ="Ming";这必然是编译不通过的,就和上面人家要传一个数组,而你却给了一个可变参数是同样的道理)
3.运行阶段不看类型匹配问题,只看这个值能否被用(即能否存在该数组中)