Java - [面向对象]方法和变量

2020/03/01

本文梳理下方法,主要涉及如下几个方面:

  • 参数传递机制
  • 可变形参
  • 递归方法

参数传递机制

Java中方法的参数参数方式只有一种: 值传递

那么什么是值传递

值传递:将实际参数值的副本(复制品)传入方法内,而参数本身不受任何影响

反正我第一次看这种文绉绉的定义,都是云里雾里的,下面我们结合例子来理解下。

首先,我们要确定一点:传入参数的类型一共有两种,要么基础类型,要么引用类型

好的,我们依次说明下。

先说基础类型

public static void swap(int a, int b){
    int tmp = a;
    a = b;
    b = tmp;
    System.out.println(String.format("in    swap(): a = %d, b = %d", a, b));
}

@Test
void primitiveTransferTest(){
    int a = 5, b = 8;
    Utils.swap(a, b);
    System.out.println(String.format("after swap(): a = %d, b = %d", a, b));
}

猜下swap()primitiveTransferTest()方法中的ab分别是多少?

// in    swap(): a = 8, b = 5
// after swap(): a = 5, b = 8

再来看下前面那句话:

值传递:将实际参数值的副本(复制品)传入方法内,而参数本身不受任何影响

也就是说,swap()方法中的abprimitiveTransferTest方法中的副本,无论swap()如何修改abprimitiveTransferTest()中的ab是不受影响的。

再来看张图,深入理解下:

再来说下引用类型

@Setter
@Getter
public class DataWrap {

    private int a;
    private int b;

    public DataWrap(int a, int b){
        this.a = a;
        this.b = b;
    }
}

public static void swapDataWrap(DataWrap dw){
    int tmp = dw.getA();
    dw.setA(dw.getB());
    dw.setB(tmp);
    System.out.println(String.format("in    swap(): a = %d, b = %d", dw.getA(), dw.getB()));
}

@Test
void referenceTransferTest(){
    DataWrap dw = new DataWrap(5, 8);
    Utils.swapDataWrap(dw);
    System.out.println(String.format("after swap(): a = %d, b = %d", dw.getA(), dw.getB()));
}

同样的问题:swapDataWrap()referenceTransferTest()两个方法中dw.adw.b分别是什么?

// in    swap(): a = 8, b = 5
// after swap(): a = 8, b = 5

swapDataWrap()收到referenceTransferTest()方法中dw引用的复制品,它也指向堆内存中的DataWrap对象。

如下图所示:

所以,在swapDataWrap()中修改ab后,本体也随之改变。

可变形参

之前在翻源码的时候,经常在方法的形参列表中能看到这种写法Type...

原来这就是所谓的可变形参,也就是说方法允许传入数量不确定的形参。

但是,还有有几个限制的:

  • 可变形参只能放在参数列表末尾。
  • 一个方法中最多只能有一个数量可变的形参。
  • 可变形参中的类型都是一样的。

举个例子:

public static void paramDynamic(int a, String... names){
    for (var name: names)
        System.out.println(name);
}

@Test
void parameterDynamicTest(){
    Utils.paramDynamic(10, "frankie", "asan", "paangzi");
    // String[] names = {"frankie", "asan", "paangzi"};
    // Utils.paramDynamic(20, names);
}

// frankie
// asan
// paangzi

可变参数的本质就是一个数组类型的形参,所以你也可以传入一个数组。

递归方法

递归就是在方法内部调用自身。

这大多数人都知道,讲个有意思的地方:

要往已知的方向递归。

来看两个例子:

f(0) = 1, f(1) = 4, f(n + 2) = 2 * f(n + 1) + f(n), 求f(10)。

public static int func(int n){
    if (n < 0) throw new RuntimeException("Please enter valid number!");
    else if (n == 0) return 1;
    else if (n == 1) return 4;
    // f(n) = 2f(n - 1) + f(n - 2)
    else return 2 * func(n -1 ) + func(n - 2);
}

@Test
void recursionTest(){
    int ret = Utils.func(10);
    Assert.assertEquals(ret, 10497);
}

f(20) = 1, f(21) = 4, f(n + 2) = 2 * f(n + 1) + f(n), 求f(10)。

public static int fn(int n){
    if (n == 20) return 1;
    else if (n == 21) return 4;
    // f(n) = f(n + 2) - 2f(n + 1)
    else return fn(n + 2) - 2 * fn(n + 1);
}

@Test
void recursionTest(){
    int ret = Utils.fn(10);
    System.out.println(ret);
}

变量

再来介绍下变量。

Java中一共有几种类型的变量?

public class FiveVariable {

    private       String instanceVariable = "instanceVariable";
    public static String staticVariable   = "staticVariable";

    public void getName(String formalParameter){
        String methodLocalVariable = "methodLocalVariable";
    }

    {
        String blockLocalVariable = "blockLocalVariable";
    }
}

一共有五种,分为两类:

  • 成员变量
    • 实例成员变量: instanceVariable
    • 类成员变量: staticVariable
  • 局部变量
    • 形参: formalParameter
    • 方法局部变量: methodLocalVariable
    • 代码块局部变量: blockLocalVariable

reference

  • 《疯狂Java讲义》 - 5.2 方法详解


一位喜欢提问、尝试的程序员

(转载本站文章请注明作者和出处 姚屹晨-yaoyichen

Post Directory