Day09 方法知识点综合(求值策略与可变参数)

发布时间 2023-12-04 17:44:36作者: 问稻

1. 求值策略

编程语言中方法之间进行参数传递时有个传递策略,该策略就被称为求值策略(Evaluation strategies)。求值策略分为两大基本类型,如果按照如何处理传递给方法的实际参数,分为严格的和非严格的两种求值策略

1.1 严格求值策略

  • 传值调用(Call by value)

    将实参复制一份给形参,修改形参不会对实参造成影响。形式参数拿到的只是一个"局部拷贝"。

  • 传引用调用(Call by reference)

    在方法调用时将引用类型的实参地址值 复制 一份传递给形参,相当于形参和实参指向了同一个内存地址。引用传递会将实参的地址传递给形参,修改形参也就是在修改实参。

  • 传共享对象调用(Call by sharing)

    在传共享对象调用中,先获取到实际参数的地址,然后将其复制,并把该地址的拷贝传递给被调方法的形式参数。因为参数的地址都指向同一个对象

    注意

    • 用类类型做形参时c++是调用拷贝构造函数创建整个类的副本,所以不会影响原值。
    • java 用类类型做形参时, 传的是原值的地址,修改形参会影响原值
    public class ShareObject {
        public static void main(String[] args) {
            //待共享对象
            ShareObject shObj= new ShareObject(10);
            System.out.println("修改前的值"+ shObj.geti());//修改前的值10
            //
            changeByShareObject(shObj);
            System.out.println("通过共享对象传递修改后的值"+ shObj.geti());//通过共享对象传递修改后的值20
            /*
            * 1.创建了一个共享对象的类 shareObject,该类包含了一个私有成员变量i,
            * 2.调用 changeByShareObject 方法传递了 shObj 的引用在该方法中,修改了 i 的值为20.
            * 3.比较调用 changeByShareObject(ShareObject Obj) 前后 i 的值可以得出 Obj 可以改变 shObj 中 i 的值
            * */
    
        }
        private int i;//私有实例变量
    
        public void seti(int value){
            this.i=value;//通过方法修改实例变量的值
        }
        public int geti(){
            return this.i;
        }
        public ShareObject(int value){
            this.i=value;//构造函数
        }
        public static void  changeByShareObject( ShareObject Obj){
            Obj.seti(20);//共享对象调用改值
        }
    }
    
1.1.1 传共享对象调用 到底是 传值调用 还是 传引用调用 的特例

从过程来看,都是复制了实参的地址传给形参,通过修改形参也可以实现修改实参。所以 传共享对象调用 会是传引用调用吗?

《The Java™ Tutorials》中Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object’s fields can be changed in the method, if they have the proper access level.

java 把传对象也认为是传值,应该把其归类为传值调用。其实也很好理解:

  1. new 出来的对象是地址映射型的,[key] [addr]。把该实参的本质当作是一种映射关系
  2. 把地址复制过去的这一步不就是在赋值映射关系吗,这也就成了传值调用。
  3. 一句话:共享对象传递就是值传递,传递的值是对象的引用
1.1.2 总结

总之,在Java方法传参时,无论传递的参数是基本类型还是引用类型,都是值传递!切记一点,Java里面只有值传递,没有引用传递!

1.2 非严格求值策略

2.可变参数

Java中的方法是可以带有多个参数的,理论上是可以无限个。但实际上一个方法的参数最好不要超过5个。在Java 5中提供了一个可变长参数,该参数允许我们在调用方法时传入不定长度的参数。其实本质上是基于数组来实现的。所以当我们不确定一个方法需要处理的参数个数时,都可以使用可变长参数。

方法名(形参1, 形参2, ...){} // 此处点点点就是可变参数的意思
  • 可变参数的格式,就是在方法最后一个形参的后面加上三个点 “…“,表示该形参可以接受多个参数值,多个参数值会被当成数组传入。

  • 可变参数只能作为方法的最后一个参数,该参数的前面可以有也可以没有其他参数

  • 由于可变参数必须是最后一个参数,所以一个方法最多只能有一个可变参数

  • Java的可变参数,会被编译器转型为对应类型的数组

  • 可变参数在编译为字节码后,在方法签名中是以数组形态出现的。这两个方法的签名是一致的,不能作为方法的重载。如果同时出现,是不能编译通过的。可变参数可以兼容数组,反之则不成立。

public static void main(String[] args) {} //不兼容下面式子
public static void main(String... args) {} //兼容上式子,等价于上式