1. 程式人生 > >Java - 傳參到底是哪種? pass by value or pass by reference

Java - 傳參到底是哪種? pass by value or pass by reference

在瞭解Java傳引數是pass by value或是pass by reference之前,先了解=賦值的用法會對理解傳參很有幫助

  • 賦值(=)的用法

    • =的意義是賦值,但是這個賦值用在 基本型別 和 物件型別 上會有非常大的差別

      • 如果=用在基本型別上,因為基本型別儲存了實際的數值,所以在為其賦值時,是直接將值複製一份新的過去

        • 因此假設a、b都是基本型別,如果執行了a=b,那麼就是將b的內容直接複製一份新的給a,之後如果改變了a的值,也不會影響到b

        • 此處的基本型別,泛指 int、long、boolean....和其包裝型態 Integer、Long、Boolean....,只要是這些型別的變數,都適用基本型別的=

          規則

      • 但如果=用在物件型別上,因為在使用物件操作時,實際儲存的其實是物件的引用,所以在為其賦值時,實際上只是把 "引用" 從一個地方複製到另一個地方

        • 因此假設c、d都是物件型別,如果執行了c=d,那麼c和d都會指向原本只有d指向的那個物件,而原本c的那個物件因為沒人引用了,所以會被垃圾回收清理掉

    • 具體例項

      • t1、t2是基本型別的=效果,t3、t4是物件型別的=效果

      class Tank {
          int level;
      }
      ​
      public class Main {
          public static void main(String[] args) throws InterruptedException {
              Tank t1 = new Tank();
              Tank t2 = new Tank();
      ​
              t1.level = 1;
              t2.level = 2;
              System.out.println("t1: " + t1.level + ", t2: " + t2.level);
      ​
              t1.level = t2.level; //此處只是基本型別的賦值,所以t1、t2仍舊指到兩個不同物件
              System.out.println("t1: " + t1.level + ", t2: " + t2.level);
      ​
              t1.level = 100;
              System.out.println("t1: " + t1.level + ", t2: " + t2.level);
      ​
              System.out.println("----");
      ​
              Tank t3 = new Tank();
              Tank t4 = new Tank();
      ​
              t3.level = 3;
              t4.level = 4;
              System.out.println("t3: " + t3.level + ", t4: " + t4.level);
              
      ​        //此處是物件型別的賦值,所以是t3和t4都指到了同一個物件上
              //而原本t3那個物件因為沒人引用了,所以會被垃圾回收清理掉
              t3 = t4;
              System.out.println("t3: " + t3.level + ", t4: " + t4.level);
      ​
              t3.level = 100;
              System.out.println("t3: " + t3.level + ", t4: " + t4.level);
      ​
          }
      }
      t1: 1, t2: 2
      t1: 2, t2: 2
      t1: 100, t2: 2
      ----
      t3: 3, t4: 4
      t3: 4, t4: 4
      t3: 100, t4: 100
  • pass by value 和 pass by reference

    • =一樣,只要掌握好基本型別實際儲存的是"值",而物件型別儲存的是"引用",就能瞭解到底是pass by value還是pass by reference

      • 基本型別 pass by value,物件型別 pass by reference

        class Tank {
            int level;
        }
        ​
        public class Main {
            public static void main(String[] args) throws InterruptedException {
                Tank t1 = new Tank();
                Tank t2 = new Tank();
        ​
                t1.level = 1;
                System.out.println("t1.level: " + t1.level);
                fooInt(t1.level); //基本型別pass by value
                System.out.println("t1.level: " + t1.level);
        ​
                t2.level = 2;
                System.out.println("t2.level: " + t2.level);
                fooTank(t2); //物件型別pass by reference
                System.out.println("t2.level: " + t2.level);
            }
        ​
            public static void fooTank(Tank tank){
                tank.level = 1000;
            }
        ​
            public static void fooInt(int level){
                level = 5;
            }
        }
        t1.level: 1
        t1.level: 1
        t2.level: 2
        t2.level: 1000
      • 基本型別的List、Set、Map 也是pass by value,物件型別的List、Set、Map是pass by reference

        class Tank {
            int level;
        }
        ​
        public class Main {
            public static void main(String[] args) throws InterruptedException {
                List<Tank> tankList = new ArrayList<>();
                List<Integer> intList = new ArrayList<>();
        ​
                for (int i = 1; i <= 2; i++) {
                    Tank tank = new Tank();
                    tank.level = i;
                    tankList.add(tank);
        ​
                    intList.add(i * 100);
                }
        ​
                System.out.println("intList: " + intList.get(0) + ", " + intList.get(1));
                fooIntList(intList);
                System.out.println("intList: " + intList.get(0) + ", " + intList.get(1));
        
                System.out.println("tankList: " + tankList.get(0).level + ", " + tankList.get(1).level);
                fooTankList(tankList);
                System.out.println("tankList: " + tankList.get(0).level + ", " + tankList.get(1).level);
            }
        ​
            public static void fooTankList(List<Tank> tankList) {
                for (Tank tank : tankList) {
                    tank.level = 500;
                }
            }
        ​
            public static void fooIntList(List<Integer> intList) {
                for (Integer i : intList) {
                    i = 2000;
                }
            }
        }
        intList: 100, 200
        intList: 100, 200
        tankList: 1, 2
        tankList: 500, 500