• 对JavaBean创建的一点改进


    在看了《Effective Java》Item2中对JavaBean的描述后,再结合Item1和Builder模式,遂想有没有其他方式避免JavaBean创建的线程安全问题呢?

    以如下JavaBean类为例,

    public class JavaBean {
    
        private int count;
        private String level;
        private List<String> messages;
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
        public String getLevel() {
            return level;
        }
    
        public void setLevel(String level) {
            this.level = level;
        }
    
        public List<String> getMessages() {
            return messages;
        }
    
        public void setMessages(List<String> messages) {
            this.messages = messages;
        }
    }

    分步创建对象如下,因为几个set方法的调用导致对象的状态可能不一致,存在线程安全问题。比如javaBean对象在执行一系列set方法过程中,其他线程调用get方法,这时得到的属性值可能就不对了。

    JavaBean javaBean = new JavaBean();
    javaBean.setCount(1);
    javaBean.setLevel("first");
    javaBean.setMessages(new ArrayList<String>());

    为了避免创建过程中被访问,可以用匿名对象+链式调用的方式,如下代码,

    public class JavaBean {
    
        private int count;
        private String level;
        private List<String> messages;
    
        public int getCount() {
            return count;
        }
    
        public JavaBean setCount(int count) {
            this.count = count;
            return this;
        }
    
        public String getLevel() {
            return level;
        }
    
        public JavaBean setLevel(String level) {
            this.level = level;
            return this;
        }
    
        public List<String> getMessages() {
            return messages;
        }
    
        public JavaBean setMessages(List<String> messages) {
            this.messages = messages;
            return this;
        }
    }
    JavaBean javaBean1 = new JavaBean().setCount(1).setLevel("second").setMessages(new ArrayList<String>());
    System.out.println(javaBean1.getLevel());

    以上写法只有对象完全初始化好后,才将引用赋给javaBean1,避免创建过程中被其他线程访问。

    但这个时候,以上分步创建对象的方式仍然可以用。怎么能强制使用链式调用呢?想来想去觉得还得对链式调用进行封装。

    增加如下代码,

    private JavaBean(){ }
    
    public static JavaBean newInstance(){
        return new JavaBean();
    }
    
    public static JavaBean newInstance(int count, String level){
        return new JavaBean().setCount(count).setLevel(level);
    }

    这样一来,实际上跟直接使用参数化的构造函数一样,如下

    public JavaBean(){ }
    
    public JavaBean(int count, String level){
        this.count = count;
        this.level = level;
    }

    总结:

    1. 在写JavaBean时,set方法尽量返回JavaBean类型;

    2. 在创建对象时,尽量使用链式调用。

  • 相关阅读:
    使用apt-mirror建立本地debian仓库源
    在MacOS上利用docker构建buildroot
    mac开发错误:errSecInternalComponent
    NFS作为根文件系统,挂载超时
    关于物体 '固有类别' 与 '实际使用类别' 分离的情况,结构体定义方法
    Crontab could not create directory .ssh
    mac bash_profile
    Mac bash rc
    watchtower无法自动更新镜像的解决方法
    spring security oAuth2.0 数据库说明
  • 原文地址:https://www.cnblogs.com/hello-yz/p/9844676.html
Copyright © 2020-2023  润新知