重视基础~Java方法(函数)中参数的传递

7 篇文章 0 订阅

做了挺长时间开发之后就会陷入一个思维定式,往往喜欢复制某些功能逻辑现有的实现方式
比如我们查出来了一个列表放入List之后,有时候需要对列表进行其他属性的填充,一般会写成如下形式

List<User> users = ...;

fillItems(users);

private void fillItems(List<User> users) {
    // 忽略其他逻辑判断 todo 
    for (User user : users) {
        // 获取其他属性并填充进user对象
        user.setXxx(xx);
    }
}

于是乎就会忽视了为什么这段代码有用,并且想当然的认为这样形式的代码都是有效的,于是有了下面的代码

public List<XxxDomain> findByDeptId(Integer deptId) {
    getDeptId(deptId);
    YyyDomain yyyDomain = yyyService.find(deptId);
}

private void getDeptId(Integer deptId) {
    Integer staffId = SecurityContextHelper.getCurrentUserId();
    if (deptId == null || deptId <= 0) {
        StaffDomain staffDomain = staffService.find(staffId);
        if (staffDomain != null) {
            deptId = staffDomain.getGid();
        }
    }
    CheckUtil.checkBusiness(deptId == null || deptId <= 0, "未获取到合法的部门信息");
}

毫无疑问 认为getDeptId方法会填充上正确的deptId并返回
但是 并没有,在执行 yyyService.find(deptId)的时候 deptId依然是当前方法findByDeptId传入的参数deptId 值并未发生变化,问题出在哪里呢?
于是回想起,Java方法中参数传递的是什么,为什么fillItems会成功而getDeptId失败呢?于是做了如下测试

注意:本次测试环境为jdk1.8,有基本数据类型常量池和字符串常量池

先测试基本数据类型int

    public static void main(String[] args) {
        // 基本数据类型测试
        int intNum = -1;
        System.out.println(intNum);
        updateInteger(intNum);
        System.out.println(intNum);
    }
    
    public static void updateInteger(int num) {
        num = 100;
    }

输出结果为

-1
-1

 对代码进行反汇编:

public static void main(java.lang.String[]);
    Code:
       0: iconst_m1
       1: istore_1
       2: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       5: iload_1
       6: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
       9: iload_1
      10: invokestatic  #4                  // Method updateInteger:(I)V
      13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_1
      17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      20: return

  public static void updateInteger(int);
    Code:
       0: bipush        100
       2: istore_0
       3: return

发现main方法中code:9和10是加载了变量intNum进入updateInteger方法,updateInteger方法中只将100压入栈赋给了方法内局部变量(istore_0);与main方法中的intNum并无关联。

 

测试String类型

    public static void main(String[] args) {
        // String类型测试
        String str = "A";
        System.out.println(str);
        updateString(str);
        System.out.println(str);
    }

    private static void updateString(String str) {
        str = "B";
    }

结果

A
A

反汇编

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String A
       2: astore_1
       3: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       6: aload_1
       7: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      10: aload_1
      11: invokestatic  #5                  // Method updateString:(Ljava/lang/String;)V
      14: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      17: aload_1
      18: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      21: return

  public static void updateString(java.lang.String);
    Code:
       0: ldc           #6                  // String B
       2: astore_0
       3: return

与int类型类似

 

测试引用类型 修改自定义对象的属性

    public static void main(String[] args) {
        // 引用类型 对象属性修改测试
        User user = new User("name", 27);
        System.out.println(user.toString());
        updateUser(user);
        System.out.println(user.toString());
    }

    public static void updateUser(User user) {
        user.setAge(100);
        user.setName("newName");
    }

static class User {
        private String name;
        private Integer age;

        public User() {
        }

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

结果

User{name='name', age=27}
User{name='newName', age=100}

反汇编

 public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/study/base/MethodTest$User
       3: dup
       4: ldc           #3                  // String name
       6: bipush        27
       8: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: invokespecial #5                  // Method com/study/base/MethodTest$User."<init>":(Ljava/lang/String;Ljava/lang/Integer;)V
      14: astore_1
      15: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      18: aload_1
      19: invokevirtual #7                  // Method com/study/base/MethodTest$User.toString:()Ljava/lang/String;
      22: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      25: aload_1
      26: invokestatic  #9                  // Method updateUser:(Lcom/study/base/MethodTest$User;)V
      29: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      32: aload_1
      33: invokevirtual #7                  // Method com/study/base/MethodTest$User.toString:()Ljava/lang/String;
      36: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      39: return

  public static void updateUser(com.study.base.MethodTest$User);
    Code:
       0: aload_0
       1: bipush        100
       3: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6: invokevirtual #10                 // Method com/study/base/MethodTest$User.setAge:(Ljava/lang/Integer;)V
       9: aload_0
      10: ldc           #11                 // String newName
      12: invokevirtual #12                 // Method com/study/base/MethodTest$User.setName:(Ljava/lang/String;)V
      15: return

 

测试引用类型 修改自定义对象为新对象

    public static void main(String[] args) {
        // 引用类型 对象重新赋值测试
        User user = new User("name", 27);
        System.out.println(user.toString());
        updateUserNew(user);
        System.out.println(user.toString());
    }

    private static void updateUserNew(User user) {
        user = new User();
        user.setAge(100);
        user.setName("newName");
    }

结果

User{name='name', age=27}
User{name='name', age=27}

反汇编

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/study/base/MethodTest$User
       3: dup
       4: ldc           #3                  // String name
       6: bipush        27
       8: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: invokespecial #5                  // Method com/study/base/MethodTest$User."<init>":(Ljava/lang/String;Ljava/lang/Integer;)V
      14: astore_1
      15: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      18: aload_1
      19: invokevirtual #7                  // Method com/study/base/MethodTest$User.toString:()Ljava/lang/String;
      22: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      25: aload_1
      26: invokestatic  #9                  // Method updateUserNew:(Lcom/study/base/MethodTest$User;)V
      29: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      32: aload_1
      33: invokevirtual #7                  // Method com/study/base/MethodTest$User.toString:()Ljava/lang/String;
      36: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      39: return

  public static void updateUserNew(com.study.base.MethodTest$User);
    Code:
       0: new           #2                  // class com/study/base/MethodTest$User
       3: dup
       4: invokespecial #10                 // Method com/study/base/MethodTest$User."<init>":()V
       7: astore_0
       8: aload_0
       9: bipush        100
      11: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: invokevirtual #11                 // Method com/study/base/MethodTest$User.setAge:(Ljava/lang/Integer;)V
      17: aload_0
      18: ldc           #12                 // String newName
      20: invokevirtual #13                 // Method com/study/base/MethodTest$User.setName:(Ljava/lang/String;)V
      23: return

上面两个测试结果不同,因为传入updateUser(New)中的user对象其实为user对象的副本,虽然是副本,但是副本和main中的user都指同一个地址,如果我们在方法中修改了对象的属性值,这时并未改变对象引用的地址;但是如果new了新的对象,方法内user就指向了新的对象地址,main方法中的user还是指向原地址。

 

总结:在Java方法中参数列表有两种类型的参数,基本类型和引用类型。

基本类型:值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。

引用数据类型:指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值