当前位置: 首页 > article >正文

重构函数-Remove Assignments to Parameters移除对参数的赋值动作七

重构函数-Remove Assignments to Parameters移除对参数的赋值动作七

1.移除对参数的赋值动作

1.1.使用场景

这个构造手法使用场景和Java的传参机制有关系,因此在介绍它使用场景前必须先介绍清楚Java传参机制才好理解它的使用场景。

1.Java传参机制定论

Java传参使用在函数的参数上,定义函数参数就是形参,调用函数传递参数就是实参。因此要问问调用函数传递的参数是值传递,还是引用传递

Java的设计是值传递,没有引用传递

2.值传递和引用传递区别

值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

3.Java是值传递论点

通常在理解Java参数传递时会有个误解:传递的参数如果是基本类型,那就是值传递,如果是对象,那就是引用传递。

Java基本类型值传递论点

public class NoLocalVariables {
    public static void change(int i) {
        i = 20;
        System.out.println("after change i = " + i);
    }

    public static void main(String[] args) {
        int i = 10;
        change(i);
        System.out.println("before change i = " + i);
    }
}

在示例中定义了一个基本类型int的变量,然后在change()方法中修改其值。分别输出修改后和修改前i 的值,运行代码看下结果。

after change i = 20
before change i = 10

修改后的值没有影响修改前的值,说明java是将i 的值复制了一份传给change()方法。结论基本类型是值传递。

Java引用类型值传递论点

class User {
    String name;
    public String getName() {
        return name;
    }

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

}
public class NoLocalVariables {
    public static void change(User s) {
        s.setName("李四");
        System.out.println("after change s = " + s.getName());
    }

    public static void main(String[] args) {
        User s = new User();
        s.setName("张三");
        //将对象引用地址复制一份传递给方法
        change(s);
        System.out.println("before change s = " + s.getName());
    }
}

创建一个User类对象表示引用类型,调用change()方法,此时Java将User对象引用地址复制了一份作为参数传递给change()方法,由于复制的地址都指向同一个对象,所以修改User对象值后该值改变了。

after change s = 李四
before change s = 李四

Java常量类型值传递论点
在Java中String类优点特殊,他是一个常量类。通过下面的源码可以看出它的存放数据是一个常量char类型的数组,所以它的数据是存放到常量池。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

通过字面量方式创建String对象,

public class NoLocalVariables {
    public static void change(String s) {
        s = "s2";
        System.out.println("after change s = " + s);
    }

    public static void main(String[] args) {
        String s = "s1";
        change(s);
        System.out.println("before change s = " + s);
    }
}

将String对象作为参数传入change方法后,修改它的值。因为字符串值是存在常量区,而常量区中相同的值只创建一次,当值不相同时就会在常量池中创建一个地址存放值,因此两个值不相同。

after change s = s2
before change s = s1

4.移除对参数的赋值动作使用场景

介绍完Java参数传递方式后,再来介绍使用场景就简单了。
当我们对参数做赋值操作后就改变了foo,然后又将另一个对象赋值给foo。造成 pass by value(传值〕和pass by reference (传址)这两种参数传递方式混淆,降低了代码的清晰度。

void aMethod(Object foo) {
	// 修改foo对象值
  foo.modifyInSomeWay();
  // 将foo指向另一个对象
  foo = anotherObject;

1.2.如何使用

  • 建立一个临时变量,把待处理的参数值赋予它。
  • 以「对参数的赋值动作」为界,将其后所有对此参数的引用点,全部替换为「对此临时变量的引用动作」。
  • 修改赋值语句,使其改为对新建之临时变量赋值。
  • 编译,测试。
  • 如果代码的语义是 pass by reference,请在调用端检查调用后是否还使用了这个参数。
  • 也要检查有多少个 pass by reference参数「被赋值后又被使用」。
  • 请尽量只以return方式返回一个值。
  • 如果需要返回的值不只一个,看看可否把需返回的大堆数据变成单一对象,或千脆为每个返回值设计对应的一个独立函数。

1.3.示例

   int discount (int inputVal, int quantity, int yearToDate) {
       if (inputVal > 50) inputVal -= 2;
       if (quantity > 100) inputVal -= 1;
       if (yearToDate > 10000) inputVal -= 4;
       return inputVal;
   }

以临时变量取代对参数的赋值动作,得到下列代码

   int discount (int inputVal, int quantity, int yearToDate) {
     int result = inputVal;
       if (inputVal > 50) result -= 2;
       if (quantity > 100) result -= 1;
       if (yearToDate > 10000) result -= 4;
       return result;
   }

http://www.kler.cn/a/793.html

相关文章:

  • GitLab 服务变更提醒:中国大陆、澳门和香港用户停止提供服务(GitLab 服务停止)
  • 基础12 友元相关
  • @RequestParam和@PathVariable的解释与区别
  • 基于 Python 大数据的拼团购物数据分析系统的设计与实现
  • 每天40分玩转Django:Django静态文件
  • 学习threejs,THREE.CircleGeometry 二维平面圆形几何体
  • HTML樱花飘落
  • 【Linux】进程管理之kill、killall、pkill
  • OpenAI GPT-4震撼发布:多模态大模型
  • Floyd算法求解最短路径
  • 道阻且长,未来可期,从GPT-4窥得通用人工智能时代的冰山一角!
  • 总结vue2基础面试
  • 常见的系统架构
  • Java数据结构 - LinkedHashMap 与 LruCache
  • 星戈瑞-Sulfo-Cyanine3 azide?磺酸基-Cy3-N3叠氮基水溶性染料
  • 文心一言---中国版的“ChatGPT”狂飙的机会或许要出现了
  • 【华为机试真题 Python实现】2023年1、2月高频机试题
  • 云原生之docker容器监控详解(cAdvisor、node exporter、prometheus)
  • 解决 IDA 防F5转伪C笔记
  • 站上风口,文心一言任重道远
  • 数字信号处理:滤波、频谱
  • Linux下gdb调试快速入门
  • 怎么避免服务内存溢出?
  • 贯穿设计模式第一话--单一职责原则
  • 【云原生|Docker】01-docker简介
  • 数据结构--二叉树