局部变量与全局变量

  • 变量的作用域
  • 基本数据类型变量与引用数据类型变量

变量的作用域

Java中变量的作用域可以分为四个级别:类级(类变量),对象实例级(实例变量),方法级(局部变量),块级(局部变量)

类型 从属于 声明位置 作用域 初始化
类变量(静态变量) 类内部,方法外,static修饰 与类同在,类被加载静态变量就有效,直至类被回收机制回收时消失 必须先声明、初始化,才能使用
成员变量(实例变量) 对象实例 类内部,方法外 有对应的实例对象创建时创建成员变量;对象消失时,成员变量消失 不用自行初始化,默认初始值
局部变量 方法 / 代码块 方法中或代码块内 从声明时开始,到所在的方法或代码块执行完毕时消失 不用自行初始化,默认初始值
// 实例代码:
public class Variable {
    // 静态变量 想使用这类变量,直接 类名.参数名 
    static String staticVariable = "我是静态变量";
    // 实例变量 想使用要先创建实例对象,如果不初始化,String会默认null,int会默认0
    String instanceVariable;
    int age;

    void Hello() {
        // 局部变量 你在这个方法中声明它,那就只能在这个方法中使用它,随着方法结束,他就会消失
        String name = "IT蛋";
        System.out.println("Hello "+name);
        System.out.println(Variable.staticVariable);
    }

    public static void main(String[] args) {
        // 局部变量,code2尝试在代码块外定义,在代码块中赋值;code3尝试重复定义
        String code2, code3;
        {
            code2 = "happy";	   // 成功,赋值并输出
            //String code3 = "happy"; 报错,已经在包含改范围的范围内定义了code3
            
            // 局部变量 你在这个代码块中声明它,就只能在这个代码块中使用它
            String code = "System.out.println('代码块内的局部变量');";
        }

        System.out.println(Variable.staticVariable);
        System.out.println(new Variable().instanceVariable);
        System.out.println(new Variable().age);
        new Variable().Hello();
        System.out.println(code2);
        // System.out.println(name)   报错,找不到属性
        // System.out.println(code)   报错,找不到属性
    }
}

---输出---
我是静态变量
null
0
Hello IT蛋
我是静态变量
happy

对于局部变量,如果存在方法内部递归调用,每次在方法中的参数都是单独存在的,如下面的fun方法,方法中的mid递推了五次,因为内部递归不会影响到外部,所以我们可以看到输出的值由顺序1-5后又从5-1输出,为了区分输出语句,我在递归返回当前方法的输出中加了个 “ | “ 。

public class Variable2 {
    public static void main(String[] args) {
        for(int i=0; i<3; i++) {
            // 局部变量 i
            System.out.print(i + " ");
        }
        // System.out.println(i);
        System.out.println();
        System.out.println("------------");
        int[] nums = new int[]{1,2,3,4,5};
        fun(nums,0);
    }

    static void fun(int[] nums, int i){
        int mid = nums[i];
        System.out.print(mid + " ");
        if(i<nums.length-1)
            fun(nums,i+1);
        System.out.print(mid + "| ");
        return;
    }
}

---输出---
0 1 2 
------------
1 2 3 4 5 5| 4| 3| 2| 1| 

实例题目:Day15_树的遍历_剑指Offer | IT蛋的个人博客 (xcscx.github.io)

// 部分代码:对于target(形参)作用域与方法变量(局部变量)一致
public void findWay(TreeNode root, int target) {
    ...
    // 传入方法的target不论怎么变,当前的target都不会收到影响,好比是复制了一份丢给方法,本体不受影响
    findWay(root.left, target);
    findWay(root.right, target);
    ...    
}

基本数据类型变量与引用数据类型变量

变量的属性会影响变量的传递:

  • 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值
  • 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值
public class Variable3 {
    public static void main(String[] args) {
        int[] nums = new int[]{1,2,3,4,5};
        int a = 22;
        System.out.println("a = " + a);
        System.out.print("nums = ");
        for(int num : nums) System.out.print(num+" ");
        System.out.println();
        System.out.println("-----");
        change(nums, a);
        System.out.println("a = " + a);
        System.out.print("nums = ");
        for(int num : nums) System.out.print(num+" ");
    }

    static void change(int[] nums, int a) {
        nums[1] = 0;
        a = 100;
    }

---输出---
a = 22
nums = 1 2 3 4 5 
-----
a = 22
nums = 1 0 3 4 5 

上述代码中,我们发现对于int类型的a,传递值确实如一开始说的那般,不会收到方法中修改的影响,但是int[] 的值却被修改了。

这也证明了引用类型传递的是参数的地址,所以会受到方法中修改的影响