1. 程式人生 > 實用技巧 >java-物件引用和物件本身

java-物件引用和物件本身

示意圖

應用場景

1.賦值
只有用新的物件本身直接賦值給對應引用,該物件引用的值會改變,因為物件引用指向的物件本身改變了。

2.方法入參
呼叫方法和被呼叫方法。

程式碼

import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author gzh
 * @createTime 2020/8/25 8:41 AM
 */
public class Test {
  private static final Logger log = LoggerFactory.getLogger(Test.class);

  public static void main(String[] args) {
    //
    List<User> userList = new ArrayList<User>();
    User user1 = new User();
    user1.setName("gzh1");
    userList.add(user1);

    User user2 = new User();
    user2.setName("gzh2");
    userList.add(user2);

    log.info(JSONObject.toJSONString(userList));

    //
//    for (User user: userList) { //這裡的list元素最終是舊值,因為沒有被新的物件本身直接賦值
//      log.info(JSONObject.toJSONString(user));
//      User user3 = new User();
//      user3.setName("gzh3");
//
//      user = user3;
//      log.info(JSONObject.toJSONString(user));
//    }

//    for (int i = 0; i < userList.size(); i++) { //這裡的list元素最終是新值,因為被新的物件本身直接賦值
//      //
//      User user = userList.get(i);
//
//      //
//      log.info(JSONObject.toJSONString(user));
//      User user3 = new User();
//      user3.setName("gzh3");
//      user = user3;
//
//      //
//      log.info(JSONObject.toJSONString(user));
//      userList.set(i,user);
//    }

    for (int i = 0; i < userList.size(); i++) { //同上:這裡的list元素最終是新值,因為被新的物件本身直接賦值
      //
      log.info(JSONObject.toJSONString(userList.get(i)));

      //
      User user3 = new User();
      user3.setName("gzh3");

      //
      userList.set(i,user3);
      log.info(JSONObject.toJSONString(userList.get(i)));
    }

    //
    log.info(JSONObject.toJSONString(userList));
  }
}

執行結果

19:49:39.062 [main] INFO Test - [{"name":"gzh1"},{"name":"gzh2"}]
19:49:39.064 [main] INFO Test - {"name":"gzh1"}
19:49:39.065 [main] INFO Test - {"name":"gzh3"} //因為list的元素被新的物件本身直接賦值,所以值改變了
19:49:39.065 [main] INFO Test - {"name":"gzh2"}
19:49:39.065 [main] INFO Test - {"name":"gzh3"} //同上
19:49:39.065 [main] INFO Test - [{"name":"gzh3"},{"name":"gzh3"}] //同上

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author gzh
 * @createTime 2020/8/25 8:41 AM
 */
public class Test2 {
  private static final Logger log = LoggerFactory.getLogger(Test2.class);

  public static void main(String[] args) {
    User user = new User();
    user.setName("gzh1");

    log.info("呼叫方法之前:{}",JSONObject.toJSONString(user));
    updateUser2(user);
    log.info("呼叫方法之後:{}",JSONObject.toJSONString(user));
  }

  private static void updateUser(User user) {
    //
    log.info(JSONObject.toJSONString(user));

    //
    User user2 = new User();
    user2.setName("gzh2");

    user = user2;

    //
    log.info(JSONObject.toJSONString(user));
  }

  private static void updateUser2(User user) {
    //
    log.info(JSONObject.toJSONString(user));

    user.setName("gzh2");

    //
    log.info(JSONObject.toJSONString(user));
  }
}


執行結果

19:50:35.072 [main] INFO Test2 - 呼叫方法之前:{"name":"gzh1"}
19:50:35.077 [main] INFO Test2 - {"name":"gzh1"}
19:50:35.077 [main] INFO Test2 - {"name":"gzh2"}
19:50:35.077 [main] INFO Test2 - 呼叫方法之後:{"name":"gzh2"} //因為入參仍然指向同一個物件本身,並沒有被新的物件本身重新賦值,所以入參的值(即物件本身)改變之後,入參的原始物件引用的值(即物件本身)也改變了。

總結

1.不同的物件引用,存放在不同的記憶體地址,而該記憶體地址儲存的值又是物件本身的記憶體地址,物件引用正是通過物件本身的記憶體地址指向物件本身。

2.物件引用的值(即指向的物件本身)什麼時候會被改變?什麼時候不會被改變?
只有直接賦值了新的物件本身,對應引用的值才會改變。

不同的物件引用沒有關係,1)如果被同一個物件本身賦值,那麼兩個物件引用都指向同一個物件本身,除此之外,就沒有其他的關係,不同的物件引用是互相獨立的,且他們之間沒有任何關係2)如果一個物件引用被新的物件本身賦值,另一個物件引用仍然是指向舊的物件本身,所以再次證明兩個物件引用之間是沒有任何關係的,兩個物件本身之間也是沒有任何關係的。

3.如果改的是同一個物件本身,那麼物件引用1和物件引用2的值同時改變。

4.如果物件引用2是指向了新的物件,那麼物件引用2的值改變,物件引用1的值不變。

最佳實踐

1.如果想要改變引用的值,應該直接賦值,而不是間接通過其他物件引用來改變。

2.如果是呼叫方法修改,應該通過返回值修改,而不是通過物件引用。