天天看點

每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

一、背景

之前我好多次談到:“每一個疑問背後至少有一個知識盲區,隐藏着一次極佳的學習機會”。

今天結合一個具體的案例,談談這個觀念,順便談談如何正确提問。

今天有一個朋友問到:

請教一個問題 為什麼用lombox的build建構一個對象内部持有的另外一個對象 用io的方式進行深克隆 拿到的兩個内部對象是一樣的 但是如果用set的方式給内部持有對象指派 深克隆出來的就不是同一個對象

二、解答過程

2.1 存在的問題

首先這段描述不太清楚,沒有标點。描述的問題顯然和深拷貝的概念不符,但是描述的内容無法讓解答的人有足夠的線索能夠為他解答問題。

2.2 引導

是以給出下面的回複:

1 先确認自己了解了 淺拷貝和深拷貝的概念

(之前一直強調的,是什麼,為什麼比怎麼做更重要)

2 建議你寫一個簡單的模拟的例子再發出來友善讨論,因為部分描述不太容易了解甚至有歧義

比如

“用io的方式進行深克隆 拿到的兩個内部對象是一樣的” 一樣的是指同一個對象?啥樣的IO方式?怎麼實作深克隆的?

“set的方式給内部持有對象指派” 是set内部對象,還是set内部對象的屬性

給出的進一步建議:

建議可以用commons-lang3 的 SerializationUtils.serialize 序列化為位元組數組 SerializationUtils.deserialize反序列化為對象。(怕他序列化姿勢有問題)

寫個DEMO表達的更清楚一些(友善進一步分析問題)

然後該同學發來了代碼:

附件類:

import java.io.Serializable;
@Data
@AllArgsConstructor
public class Attchment implements Serializable {
    private String name;
}      
每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

待測試類:

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WeeklyLogByIO implements Serializable {
    private String name;
    private String date;
    private String content;
    private Attchment attchment;
    public WeeklyLogByIO deepClone() throws Exception{
        //将對象寫入到流中
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //将對象從流中取出
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (WeeklyLogByIO)ois.readObject();
    }
}      
每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

測試代碼:

public class SDemo {
    public static void main(String[] args) {
         WeeklyLogByIO logProvious = new WeeklyLogByIO();
        Attchment attchment = new Attchment("附件1");
        logProvious.builder().attchment(attchment).build();
        //logProvious.setAttchment(attchment);
        //開始克隆
        WeeklyLogByIO weekNew = null;
        try {
            weekNew = logProvious.deepClone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        weekNew.setDate("第二周");
        System.out.println(logProvious == weekNew);
        System.out.println(logProvious.getAttchment() == weekNew.getAttchment());
    }
}      
每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

輸出的結果分别為 false 和 true。

和對方确認他的表達:

你表達的就是 為啥深拷貝,結果一個是 true 一個是 false 對吧,就是第二個列印語句輸出的結果不對對吧?

這才清楚明白地搞清楚他真正想表達的意思。

看了DEMO 得出了兩個結論:

1、 因為你builder 模式使用姿勢不對。builder 是靜态函數 不需要用執行個體去調用 , build 之後傳回值構造了新的對象 你并沒有拿對象去接收。

2、 你沒認真調試代碼。在第二個列印語句處斷點調試,就可以看到附件并沒有設定,兩個都是null 是以輸出 true。

3、沒認真看IDE的警告。通過類執行個體調用靜态函數會有警告的。

每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

修改一行解決問題:

public class SDemo {
    public static void main(String[] args) {
        Attchment attchment = new Attchment("附件1");
        WeeklyLogByIO logProvious = WeeklyLogByIO.builder().attchment(attchment).build();
        //logProvious.setAttchment(attchment);
        //開始克隆
        WeeklyLogByIO weekNew = null;
        try {
            weekNew = logProvious.deepClone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        weekNew.setDate("第二周");
        System.out.println(logProvious == weekNew);
        System.out.println(logProvious.getAttchment() == weekNew.getAttchment());
    }
}      
每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

然後該同學表明确實不熟悉 builder 模式,而且不熟悉 lombok。

然後我給出建議:

1、學習Builder模式

2、看 lombok官方文檔

3、直接使用反編譯工具,檢視lombok 注解編譯生成的類檔案的反編譯後的”源碼”就可以檢視注解對源碼的影響。

每一個疑問背後都隐藏着至少一個盲點和學習的絕佳機會一、背景二、解答過程三、看到了什麼四、總結

三、看到了什麼

3.1 方法的重要性

其實很多人程式設計過程中遇到問題的主要原因是學習技術不求甚解,大概看看部落格,看看别人怎麼用就用,沒有認真看官方技術文檔,沒有能夠通過更豐富的手段來學習這種技術。

是以很多人想要有較大進步,并不像一些人所想的那樣,“更加努力”,而是找到更加科學的方法。

另外我們還看到“很多人覺得某些技術沒用,就不願意學,很多時候正是因為沒學好,才在該用到的時候想不着用”。

比如我們可以通過反編譯來學習 lombok, 然而很多人想不到用,甚至從來都沒嘗試過反編譯。

3.2 如何提問

另外很多人提問都不是很清楚,對解決問題的人造成很大困難。當然我是希望大家能夠自己解決問題,這非常重要,沒有人可以一直幫你解決問題,工作之後排錯的能力更加重要。

1、提問時要盡可能地有條理表達自己的疑問,帶上序号,帶上标點,描述清楚前因後果,描述清楚核心困惑等。

2、提問之前自己一定要進行思考,提問之前一定要自己調試過,提問之前一定要自己百度過

3、提問時盡可能給出詳細的線索,比如報錯的具體内容,比如給出源碼,比如 Web 項目 F12看網絡給出請求和響應狀态等。

3.3 每一個盲點背後

每一個困惑背後至少有一個知識盲區,隐藏着一次極佳的學習機會。

該同學通過這個問題的解答,意識到了 builder 設計模式了解不到位,意識到了 lombok 注解了解的不到位。

學到了可以通過反編譯來檢視 lombok 注解對源碼的影響,直覺和快速地學習 lombok 注解。

如果是一個聰明的有心人,應該意識到自己解決問題的能力有待提高,自己連起碼的斷點調試都沒有做。

如果是一個聰明的有心人,應該會意識到今後要重視 IDE的警告,甚至安裝上推薦的 阿裡巴巴 Java 開發規範的配套插件。

如果是一個聰明的有心人,應該可以從我的回答中了解到 commons-lang3 有更簡潔地實作序列化和反序列化的工具類,進而了解 commons-lang3 中的其他好用的工具類進而提高開發效率。

如果是一個聰明的有心人,應該能夠意識到自己提問的姿勢有問題,後續提問應該更有條理,更準确的表達自己的問題。

如果是一個聰明的有心人,應該...

如果真正可以意識到這些問題,并能夠較快改正,學習的速度會有極大的提升。

四、總結

希望越來越多的同學能夠意識到方法的重要性。

希望也來越多的同學能夠知道如何提問。

希望越來越多的同學能夠意識到:每一個困惑背後至少有一個知識盲區,隐藏着一次極佳的學習機會。 的真正含義。

學習是一種能力,解決問題也是一種能力。

授人以魚不如授人以漁,同樣地,希望大家多學方法,而不是僅僅追求學習某個具體知識點,甚至以記住某個知識點為傲。

-------------------

如果你覺得本文對你有幫助,歡迎點贊、評論、轉發(請注明出處)。你的支援是我創作的最大動力。