为了账号安全,请及时绑定邮箱和手机立即绑定

每一个疑问背后都隐藏着至少一个盲点和学习的绝佳机会

标签:
Java

之前我好多次谈到:“每一个疑问背后至少有一个知识盲区,隐藏着一次极佳的学习机会”。

今天结合一个《手册》详解专栏学员的一个提问,谈谈这个观念,顺便谈谈如何正确提问。

今天有一个朋友问到:

请教一个问题 为什么用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;
}

待测试类:

mport 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");

// logProvious.builder().attchment(attchment).build(); 这行有问题,修改如下:
        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、 看官方文档

2 、直接使用反编译工具,查看Lombok 注解编译生成的类文件的反编译后的”源码”就可以查看注解对源码的影响。

图片描述

3.1 方法的重要性

其实很多人编程过程中遇到问题的主要原因是学习技术不求甚解,大概看看博客,看看别人怎么用就用,没有认真看官方技术文档,没有能够通过更丰富的手段来学习这种技术。

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

另外我们还看到:很多人觉得某些技术没用,就不愿意学,很多时候正是因为没学好,才在该用到的时候想不着用

比如我们可以通过反编译来学习 lombok, 然而很多人想不到用,甚至从来都没尝试过反编译。

3.2 如何提问

另外很多人提问都不是很清楚,对解决问题的人造成很大困难。当然我是希望大家能够自己解决问题,这非常重要,没有人可以一直帮你解决问题,工作之后排错的能力更加重要。

1、提问时要尽可能地有条理表达自己的疑问,带上序号,带上标点,描述清楚前因后果,描述清楚核心困惑等。

2、提问之前自己一定要进行思考,提问之前一定要自己调试过,提问之前一定要自己百度过

3、提问时尽可能给出详细的线索,比如报错的具体内容,比如给出源码,比如 Web 项目 F12看网络给出请求和响应状态等。

3.3 每一个盲点背后

每一个困惑背后至少有一个知识盲区,隐藏着一次极佳的学习机会。

该同学通过这个问题的解答,意识到了 builder 设计模式理解不到位,意识到了 lombok 注解了解的不到位。

学到了可以通过反编译来查看 lombok 注解对源码的影响,直观和快速地学习 lombok 注解。

如果是一个聪明的有心人,应该意识到自己解决问题的能力有待提高,自己连起码的断点调试都没有做。

如果是一个聪明的有心人,应该会意识到今后要重视 IDE的警告,甚至安装上推荐的 阿里巴巴 Java 开发规范的配套插件。
如果是一个聪明的有心人,应该可以从我的回答中了解到 commons-lang3 有更简洁地实现序列化和反序列化的工具类,进而了解 commons-lang3 中的其他好用的工具类从而提高开发效率。

如果是一个聪明的有心人,应该能够意识到自己提问的姿势有问题,后续提问应该更有条理,更准确的表达自己的问题。

如果是一个聪明的有心人,应该…

如果真正可以意识到这些问题,并能够较快改正,学习的速度会有极大的提升。

希望越来越多的同学能够意识到方法的重要性。
所谓“外行人看热闹,内行人看门道”,一个简单问题背后有些人就只要答案即可,有些人却能够发现很多问题,这也决定这很多人成长的快慢,希望本文能够对一些同学有启发。

希望也来越多的同学能够知道如何提问。

希望越来越多的同学能够意识到:每一个困惑背后至少有一个知识盲区,隐藏着一次极佳的学习机会。 的真正含义。

学习是一种能力,解决问题也是一种能力。

授人以鱼不如授人以渔,同样地,希望大家多学方法,而不是仅仅追求学习某个具体知识点,甚至以记住某个知识点为傲。


如果本文对你有帮助,欢迎点赞、评论和转发,你的支持是我创作的最大动力。

另外想学习,更多开发和避坑技巧,少走弯路,请关注我的专栏:《阿里巴巴Java 开发手册》详解专栏

点击查看更多内容
6人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
3857
获赞与收藏
1465

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消