好吧标题说明了一切。
例如,我有一个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。哪种方法更可取?或者我应该使用任何其他方法吗?
答案 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时都要复制
但你也应该考虑每次复制的代码。出于这个原因,我们已经禁用了此规则并接受此漏洞。