2

好吧,标题说明了一切。

例如,我有一个 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()方法。但它返回对象。那么我应该简单地在吸气剂中进行铸造吗?:

class Employee
{
   private Date joinDate;

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

Q3。哪种方法更可取?还是我应该使用任何其他方法?

4

4 回答 4

2

我建议您声明Date Objectfinal并使用复制构造函数。

有一篇不错的文章“关于为什么 clone() 在 Java 中有很多缺点”链接

class Employee{
    private final Date joinDate;
    public Employee(Date joinDate,...){
         this.joinDate = joinDate;
    }
    public Date getJoinDate(){
         return new Date(joinDate);    
    }
}
于 2013-02-06T07:17:04.577 回答
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, 2nd Edition中提到的那样,它可能是一个安全问题:

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

现在您可以将此对象作为日期传递,并且因为调用者可以持有对该对象的引用,所以它可以操纵对象的状态,即使在克隆之后也是如此。

于 2013-02-06T07:30:13.640 回答
1

您的员工类的复制构造函数不会阻止任何人更改您返回的日期

Date.setTime(long)

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

class Employee {
   private final Date joinDate;

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

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

于 2013-02-06T07:20:28.457 回答
0

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

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

  • 每次设置 getter 时都复制一份

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

于 2013-02-06T07:23:32.813 回答