可变参数与数组(java)

前言:最近在学习可变参数的问题,许多人说可变参数就是数组,我在查了一些资料,还有向老师请教

最终结合自己的思考得出了自己的一些理解(仅供参考,若有错误还请指出)

 一.向上转型与可变参数的例题

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

可变参数与数组(java)_第1张图片

如果将上述传参改为可变参数,那么在编译阶段就会报错,原因是编译类型看左边(即父类类型),但父类中该方法要求传一个数组,你传的却是一个可变参数必然会报错.

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.运行阶段不看类型匹配问题,只看这个值能否被用(即能否存在该数组中)

你可能感兴趣的:(java,开发语言)