我应该为从getter返回的每个对象编写复制构造函数

时间:2013-02-06 07:04:58

标签: java copy-constructor getter

好吧标题说明了一切。

例如,我有一个Employee类

class Employee
{
   private Date joinDate;

   public Date getJoinDate()
   {
       return joinDate;    
   }
}

这里getJoinDate返回对内部joinDate对象的引用。当我在FindBug中分析我的代码时,它给了我一个“恶意代码漏洞”警告为“......可能通过返回ClassXYZ.pqrDate来暴露内部表示”

因此,访问此getter的任何代码都有可能修改存储在该实例外的该类实例中的日期。我应该使用复制构造函数

Q1。我是否应该编写复制构造函数(或遵循任何其他方法)

class Employee
{
   private Date joinDate;

   Employee(Employee e)      //copy constructor
   {
       joinDate = e.joinDate;
   }

   public Date getJoinDate()
   {
       return joinDate;    
   }
}

Q2如何为框架对象编写复制构造函数?我可以为业务对象定义复制构造函数,但不能为框架对象定义复制构造函数。 我是否应该拥有一个泛型util类,所有方法都返回接受实例的新框架类实例

class CopyConstructorUtil
{
    public Date copyDate(Date date)
    {
         return new Date(date.getTime());
    }
    //....
}

Java Object类确实提供了clone()方法,它由所有类继承。但它返回Object。那么我应该只是在getter内部进行投射? :

class Employee
{
   private Date joinDate;

   public Date getJoinDate()
   {
       return (Date)joinDate.clone();    
   }
}

Q3。哪种方法更可取?或者我应该使用任何其他方法吗?

4 个答案:

答案 0 :(得分:2)

我建议您将Date Object声明为final并使用复制构造函数。

有一篇很好的文章“关于为什么clone()在Java中有许多缺点”link

class Employee{
    private final Date joinDate;
    public Employee(Date joinDate,...){
         this.joinDate = joinDate;
    }
    public Date getJoinDate(){
         return new Date(joinDate);    
    }
}

答案 1 :(得分:2)

问题是Java数据类型的可变性。因此,即使使用复制构造函数,如果没有实例化新的Date,仍会泄漏对象状态。

你应该这样做(你需要修改getter和setter),否则你正在泄漏你的对象状态:

public Date getJoinDate() {
    return new Date(joinDate.getTime());
}

public void setDate(Date joinDate) {
    this.joinDate = new Date(joinDate.getTime());
}

调用clone()并不是很好,因为在提及的 Effective Java,第2版中,它可能是一个安全问题:

class MyDate extends Date {
    public Object clone() {
        return this;
    }
}

现在你可以将这个对象作为日期传递,并且因为调用者可以保存对象的引用,所以即使在克隆之后它也可以操纵对象的状态。

答案 2 :(得分:1)

您的Employees类的复制构造函数不会阻止任何人使用

更改您返回的日期
Date.setTime(long)

我会在返回之前克隆内部对象。或者不是克隆我会使用您在克隆代码之前使用的方法。像这样:

class Employee {
   private final Date joinDate;

   public Date getJoinDate() {
       return new Date(joinDate.getTime());
   }
}

此解决方案不需要强制转换,并且可以阻止任何人编辑您的内部成员。

答案 3 :(得分:0)

在我们的项目中,我们禁用了这个findbugs规则。 Findbigs是真的,date是可变对象,所以如果你真的想要阻止任何改变,你别无选择,除了:

  • 将日期作为long返回,以防止暴露实例

  • 每次设置getter时都要复制

但你也应该考虑每次复制的代码。出于这个原因,我们已经禁用了此规则并接受此漏洞。