java 和 python中参数在函数体中的改变对参数本身的影响

最近几天在看python , 看到函数这一段的时候 , 突然发现一个问题 , 字符串在函数体中重新赋值 , 不会对函数体外 , 该字符串本身的值产生影响 .
例如 :

def changestr (str):
    str = "inside" 
    print("这是function中 , 值为:",str)
mystr = "outside"
changestr(mystr)
print("这是函数外边 , 值为:",mystr)

运行结果为 :

这是function中 , 值为: inside
这是函数外边 , 值为: outside

考虑到字符串不可变的特性 (python的六种标准类型 , 其中有三种是不可变的类型 , 即 : Number ,String , Tuple) , 我分别测试了Number和Tuple , 发现同以上结果是一样的 , 因为这三种类型只能通过重新赋值来改变对象的值 , 另外三种类型(List , Set , Dictionary) 是可以改变内部的元素 , 于是又测试了这三种seq类型 , 第一次测试如下 :

def change(mylist):
    mylist.append([1,2,3,4])
mylist = ["aa",21]
print(mylist)
change(mylist)
print(mylist)

结果如下:

['aa', 21]
['aa', 21, [1, 2, 3, 4]]

发现在函数体中的修改 , 对对象本身的值发生了改变 , 在函数之外 , 该列表的内容依然发生了改变 , 这是事先就能猜测到的结果 , 因为python中的参数 , 传入的是变量引用的副本 , 它与变量指向同一个值.
鉴于前三种类型的参数是直接重新赋值的 , 于是继续下一步测试 :

def change2(list):
    list = [1,2,3,4]
mylist = ["aa",21]
print(mylist)
change2(mylist)
print(mylist)

结果如下:

['aa', 21]
['aa', 21]

有些意外 , 出现了和三种不可变类型参数一样的情况 , 在函数体中的重新赋值 , 没有对外部变量的值产生影响 , 不过仔细一想 , 却又在情理之中 .
我对python还不够熟悉 , 但是从近两天的学习中发现 , 其存储模型与java相似 , 即变量中存储的是引用 , 是指向真正内容的内存地址(当然 ,java中的八大基本数据类型 , 变量名和值都是存储在堆栈中的 ) , 对变量重新赋值 , 相当于修改了变量副本存储的内存地址 , 而这时的变量已经和函数体外的变量不是同一个了, 在函数体之外的变量 , 依旧存储的是原本的内存地址 , 其值自然没有发生改变 .

简单来说 :
- 函数体传入的参数 , 为函数体外变量引用的副本 .
- 在函数体中改变变量指向的堆中的值 , 对函数外变量有效.
- 在函数体中改变变量的引用 , 对函数外变量无效

大致图如下 :(红色线代表重新赋值动作)
这里写图片描述

当然 , 测试时不能少的 , 我在java中也做了相应的测试 , 结果与猜想一致 , 测试代码如下:

import java.util.ArrayList;
import java.util.List;

/**
 * Created by dell on 2017/3/27.
 *
 * @author dell
 * @date 2017/03/27
 */
public class DemoScope {


    public static void main(String[] args) {
        {
            String str1 = "aaa";
            testStr(str1);
            System.out.println("方法外:"+str1);
        }
        {
            int a = 5;
            testNumber(a);
            System.out.println("方法外:"+a);
        }
        {
            List list = new ArrayList();
            list.add("a");
            list.add("b");
            testList(list);
            System.out.println("方法外:"+list.toString());
        }
        {
            char a = 'a';
            testChar(a);
            System.out.println("方法外:"+a);
        }
        {
            List list = new ArrayList();
            list.add("a");
            list.add("b");
            testList2(list);
            System.out.println("方法外:"+list.toString());
        }
        {
            boolean fl = true;
            testBoolean(fl);
            System.out.println("方法外:"+fl);
        }
        {
            Tree tree = new Tree(50 , "银杏");
            testObject(tree);
            System.out.println("方法外:"+tree.toString());
        }
        {
            Tree tree = new Tree(50 , "银杏");
            testObject2(tree);
            System.out.println("方法外:"+tree.toString());
        }

    }


    static class Tree{
        int height;
        String type;

        Tree(int height, String type){
            this.height = height;
            this.type = type;
        }

        @Override
        public String toString() {
            return "Tree{" +
                    "height=" + height +
                    ", type='" + type + '\'' +
                    '}';
        }
    }


    private static void testStr(String str){
        System.out.println("1.这是function中,str="+str);
        str = "新的值";
        System.out.println("2.这是function中,str="+str);
    }

    private static void testNumber(int num ){
        System.out.println("重新赋值前:"+num);
        num = 10;
        System.out.println("重新赋值后:"+num);
    }

    private static void testList(List list){
        System.out.println("重新赋值前:"+ list.toString());
        list.set(0, "A");
    }

    private static void testList2(List list){
        System.out.println("重新赋值前:"+ list.toString());
        list = new ArrayList();
        list.add("A");
        System.out.println("重新赋值后:"+list.toString());
    }


    private static void testChar(char a){
        System.out.println("重新赋值前:"+ a);
        a = 'A';
        System.out.println("重新赋值后:"+a);
    }


    private static void testBoolean(boolean flag){
        System.out.println("重新赋值前:"+ flag);
        flag = false;
        System.out.println("重新赋值后:"+flag);
    }

    private static void testObject(Tree obj){
        System.out.println("重新赋值前:"+obj.toString());
        obj.height = 100 ;
        System.out.println("重新赋值后:"+obj.toString());
    }

    private static void testObject2(Tree obj){
        System.out.println("重新赋值前:"+obj.toString());
        obj = new Tree(100 , "琵琶") ;
        System.out.println("重新赋值后:"+obj.toString());
    }
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值