Java 我应该为从getter返回的每个对象编写复制构造函数吗
标题说明了一切 例如,我有一个Employee类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
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;
}
}