做者:林冠宏 / 指尖下的幽靈java
掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8git
博客:http://www.cnblogs.com/linguanh/github
GitHub : https://github.com/af913337456/面試
聯繫方式 / Contact:913337456@qq.com算法
瞭解這些術語:數組
對象引用
與 對象
的區別精通java
,寫 熟練
首先明確一點,System.arraycopy 操做的是數組,效果是深複製。 是否是以爲怎麼和你印象的中不同?
重點來了,對於對象數組,例如: User[],這種數組,有一個注意點
,這個點就是:對於數組內的對象是淺拷貝。
ide
一句話:函數
System.arraycopy 對於數組是深拷貝,對於數組內的對象是淺拷貝。由於操做的傳入參數是數組,那麼迴歸本意,效果是深複製。
上面的含義必定要區分清楚! 由於如今網上不少觀點是混淆,亂JB寫的 。this
來看個例子,下面的代碼能夠本身去運行驗證。已經充分驗證了上面個人觀點。code
public class Test { public static void main(String[] args) { User[] users=new User[]{ new User("111"),new User("222"),new User("333") };//初始化對象數組 User[] target=new User[users.length];//新建一個目標對象數組 System.arraycopy(users, 0, target, 0, users.length); // 複製 System.out.println("數組地址是否同樣:"+(users == target?"淺複製":"深複製")); System.out.println("數組內對象地址是否同樣:"+(users[0] == target[0]?"淺複製":"深複製")); target[0].setEmail("444"); System.out.println("修改後輸出 users[0] ,是否和 target[0]同樣是444,users[0]:"+users[0].getEmail()); users[0] = null; // -----------------① System.out.println("遍歷 users"); for (User user : users){ System.out.println(user); } System.out.println("遍歷 target"); for (User user : target){ System.out.println(user); } users = null; if(target == null){ System.out.println("users = null 後是否 target 也變成了 null,是則證實是淺複製"); }else{ System.out.println("users = null 後是否 target 不受任何影響,是則再次證實數組是深複製"); } } } class User{ private String email; public User(String email) { this.email = email; } public String getEmail() { return email;} public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User [email=" + email+ "]"; } }
輸出的結果以下:
數組地址是否同樣:深複製 數組內對象地址是否同樣:淺複製 修改後輸出 users[0],是否和 target[0]同樣是444,users[0]:444 遍歷 users null User [email=222] User [email=333] 遍歷 target User [email=444] User [email=222] User [email=333] users = null 後是否 target 不受任何影響,是則再次證實數組是深複製
上面個人例子還留有一個經典的面試點,既是標號 ① 對應的行:
users[0] = null; // -----------------①
上面咱們談到了,數組內的對象是淺複製,那麼在上面這行我把 users[0] 下標爲0的對象弄爲 null 後。後面再遍歷輸出:
System.out.println("遍歷 users"); for (User user : users){ System.out.println(user); } System.out.println("遍歷 target"); for (User user : target){ System.out.println(user); }
明顯地,咱們能夠容易知道,user[0] 此時輸出的確定是 null。那麼 target[0] 呢?淺拷貝的話,target[0] 必然在內存地址和值上面全等於 users[0]
。
可是從 System.out.println("遍歷 target");
的結果來看。卻發現 target 輸出的是:
遍歷 target User [email=444] // 第一個不是 null User [email=222] User [email=333]
這是爲何呢?其實這是最爲基礎的: 對象引用與對象的區別
,一名合格,僅僅是合格的 Java 語言使用者,這個得知道。下面咱們來談談它。
有一個類:
public class Demo { //默認構造方法 public Demo{ } }
咱們用它建立個對象
Demo fuck = new Demo();
這一條語句,其實包括了四個動做:
堆空間
裏建立一個Demo對象。棧空間中
。也就是用來指向Demo對象的對象引用。fuck
Demo fuck;//一個對象引用 fuck = new Demo();//一個對象引用指向一個對象
一個對象能夠被多個對象引用同時引用。它們操做的始終是同一個。
Demo fuck,fuck2;//建立多個對象引用 fuck = new Demo(); fuck2 = fuck;
好了,回答以前的坑, users[0] = new User("111")
,users[0] = null
,target[0] = users[0]
,users[0] = null 只是把棧中的 users[0] 對象引用弄爲了 null,對象 new User("111") 與它無關,天然沒影響,target[0] 是另一個對象引用,也是指向了 new User("111")。
根據 大 Jvm 的 內存回收算法之根搜索,引用鏈存在、強引用、when 當前應用內存不夠了,強制拋出 OOM。那麼當 target[0] = null
,new User("111")
對應的這塊內存就會進入被回收的隊列中,「死去」。
最後這段是否是有點看不懂 ?那證實你要繼續努力了。