Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我应该为从getter返回的每个对象编写复制构造函数吗_Java_Copy Constructor_Getter - Fatal编程技术网

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

Java 我应该为从getter返回的每个对象编写复制构造函数吗,java,copy-constructor,getter,Java,Copy Constructor,Getter,标题说明了一切 例如,我有一个Employee类 class Employee { private Date joinDate; public Date getJoinDate() { return joinDate; } } 这里getJoinDate返回对内部joinDate对象的引用。当我在FindBug中分析我的代码时,它给了我一个“恶意代码漏洞”警告,“可能会通过返回ClassXYZ.pqrDate来暴露内部表示” 因此,任何访问此ge

标题说明了一切

例如,我有一个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对象类也提供了clone()方法,该方法由所有类继承。但它返回对象。那么,我是否应该简单地在getters内部进行铸造呢

class Employee
{
   private Date joinDate;

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

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

我建议您将
日期对象
声明为
最终
并使用复制构造函数

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


Employees类的副本构造函数不会阻止任何人更改您返回的日期

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

class Employee {
   private final Date joinDate;

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

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

在我们的项目中,我们已禁用此findbugs规则。Findbigs是true,date是可变对象,因此如果您真的想阻止任何更改,除了:

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

  • 每次设置getter时都要进行一次复制


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

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

您应该这样做(您需要同时修改getter和setter),否则您将泄漏您的对象状态:

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

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

调用
clone()
不太好,因为正如在《有效的Java》第二版中提到的那样,它可能是一个安全问题,如下所示:

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

现在,您可以将此对象作为日期传递,因为调用方可以保留对该对象的引用,所以即使在克隆之后,它也可以操纵对象的状态。

遗憾的是,java.util.date是可变的,Puting final不会禁止对此对象进行更改。joinDate可以为null,并且您的代码将抛出NPE。这是真的。克隆()也存在同样的问题。不,你没有得到我写代码的意图。看到它不是关于日期,而是关于返回和接受员工。Like
Employee e2=新员工(e1)
在本例中,调用
e1.setJoinDate()
不会更新e2.joinDateohkay for Date有getTime()方法,但对于其他框架类,没有这样的方法可以让我们非常轻松地创建clonned实例,那么在这些情况下该怎么办?如果有人想要攻击您的代码,使用clone()也不安全,因为可以使用其clone()方法不是默认实现的日期子类。请使用
clone
。这正是它存在的原因。@Amir:我不确定-派生类是如何进入系统的?@Eric我编辑了我的答案,并提到了clone()如何成为问题的根源。仍然没有理由不在
getJoinDate
中使用clone。在这种情况下,可以向bean注入一个变异的日期,并更改其状态,没有通知豆子。
class MyDate extends Date {
    public Object clone() {
        return this;
    }
}