2012-03-21 69 views
1

我知道,在java中传递对象时,对象的引用作为值传递。所以你对这个对象所做的任何改变都反映在原始对象中。为了避免这种情况,我们在java中使用了不变性属性。java中的不变性属性

所以我的问题是,我已经创建了一个不变Employee,当我通过这个Employee类在其他类中的一些方法的对象,我不希望这样的方法来对这个对象的任何变化。即使如此,我也不希望这些更改受到调用类中创建的原始对象的影响。

这是我的示例代码。

public final class Employee { 
    int employeeId; 

    public int getId() { 
     return employeeId; 
    } 

    public void setId(int id) { 
     this.employeeId = id; 
    } 

} 

public class Worker { 
    public static void process(Employee f, Employee g){ 
     int c = f.getId(); 
     f.setId(g.getId()); 
     g.setId(c); 
    } 
} 

public class ImmutabilityTest{ 

    public static void main(String[] args) { 
     Employee teamMember = new Employee(); 
     Employee teamLead = new Employee(); 
     teamMember.setId(5); 
     teamLead.setId(10); 
     System.out.println("Before process "+teamMember.getId() + " " + teamLead.getId()); 
     Worker.process(teamMember, teamLead); 
     System.out.println("After process "+teamMember.getId() + " " + teamLead.getId()); 
    } 
} 

输出将是

Before process 5 10 
After process 10 5 

有什么办法,以避免在Employee类的成员变量的值的变化? (除了让他们final)如果不是那么我们如何实际利用不变性在用户定义的类中的Java属性?

任何建议/意见/指针表示赞赏!谢谢..

回答

5

不变性不是Java中的属性,该属性可以被应用到对象与单个关键字,其一个需要在个案基础上实施的战略。一般而言,您使用final关键字和克隆为了完成此。请注意,物体嵌套越深,达到真实物体不变性的难度越高。

这是你的Employee类的(更)不可改变的版本:

public class Employee { 
    final int employeeId; 

    public Employee(final int id) { 
     super(); 
     this.employeeId = id; 
    } 

    public int getId() { 
     return employeeId; 
    } 
} 

注意,在Java中反射使得它几乎不可能实现真正的不变性,即使使用的最终实例变量和克隆。

+0

感谢您的洞察.. – Rakesh 2012-03-21 06:16:59

4

Employee有一个setter 有一个非私人领域,因此它是不immutable

删除setter,并使字段private,您的问题得到解决。

你的另一种选择是通过所述对象的拷贝(通常使用copy constructor创建它)

+0

即使我删除了setter,它没有任何区别。我仍然可以改变值'teamMember.id = 15' – Rakesh 2012-03-21 06:10:30

+0

@Rakesh好点 - 我编辑答案 – Bohemian 2012-03-21 06:12:42

+0

感谢您的建议.. – Rakesh 2012-03-21 06:26:59

1

您可以将setId方法的可见性更改为封装私有方式,并确保WorkerEmployee的封装格式不同。

或者完全删除setId方法。

[如果其他类进行更改]我不希望更改受到在调用类中创建的原始对象的影响。

如果你想要采取这种做法,那么你需要创建和传递原始对象的副本


需要注意的是,除非你声明的私人employeeId场是final,你不会得到永恒的全部好处。严格地说,如果有可能不同的线程在同一Employee实例上调用getId,则需要同步getId方法。

+0

感谢您的答案 – Rakesh 2012-03-21 06:25:43

0

如果你不想让别人改变你的属性值,你可以把它们保持为私人的,而不需要setter。

1

final关键字应用于类只是表示该类不能扩展(或分类)。

它与它的成员是否可以修改无关。

+0

+1:感谢您的更正,我混淆了最后和不可变的字符串类! :-) – Rakesh 2012-03-21 06:24:13