我正在阅读有关不可变类的知识,据说使类不可变的方法是:
setter
方法。我认为第三个条件是不必要的。当我们将变量定为final并为其提供任何值时,即使通过setter
方法也无法为其分配新值(因为一旦将值赋给final变量就无法更改) 。那么为什么我们需要没有设置方法的第三个条件呢?
我理解错误的方式吗?
答案 0 :(得分:0)
您是对的。根据定义,设置器将使用给定值替换字段。如果所有字段都是最终字段,那么您无论如何都无法提供设置器。
我对如何编写不可变类的描述是:
如果您非常注意确保字段不变,则可以编写一个可变字段的不可变类,但是在这种情况下,您需要非常小心。
答案 1 :(得分:0)
是的,它可以减少为
但是出于教育目的,较短的项目符号可能会更好地工作-即使有些多余。
答案 2 :(得分:0)
public class Person{
private String name;
public Person(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
现在,很明显,Person不是不可变类。这并不意味着Person的实例不能是(据说)不可变的另一个类的成员。
public final class MyImmutableClass {
// p is final, so it can't be re-referenced
private final Person p;
public MyImmutableClass(Person p) {
this.p = p;
}
// it can be altered, though
public void setPersonName(String name) {
this.p.setName(name);
}
public String toString() {
return "Person: " + p.getName();
}
}
现在,我们有一个不可变的类,但是它确实包含一个setter。该设置器会主动更改(最终)字段p的成员。
public static void main(String[] args) {
MyImmutableClass c = new MyImmutableClass(new Person("OriginalName"));
System.out.println(c);
c.setPersonName("AlteredName");
System.out.println(c);
}
然后..那里有。通过设置器更改成员(即使变量是最终的)。一定要理解,“最终变量”不一定是常数,在大多数情况下,它的状态可以更改。最终变量的意义在于它不能被重新引用。注意,我们也可以有这样一种方法:
public void setPerson(Person p) {
this.p.setName(p.getName());
}
如果类型本身是不可变类型,或者如果它是原始类型,则最终变量本身仅是常量,但是您应该了解那里的大多数类型都是可变的。 类型是不可变的还是原始的,并且被声明为final?当然,添加一个二传手。但是,目的是什么?误导使用您班级的人?
答案 3 :(得分:0)
项目2中提到的变量可以是引用,即使变量本身为final
,也可以是可变的(如列表或集合)。
这就是为什么我们拥有Collections.unmodifiableList
之类的实用程序来使可变类几乎不变的原因。
因此,对setter的禁止是为了防止意外更改最终变量的状态。
答案 4 :(得分:0)
将字段最终定为不足以保证不变性。您需要在不可变的类中制作可变对象的防御性副本。
class Foo {
private String str;
public Foo(String str) {
this.str = str;
}
public String getString() {
return str;
}
}
上面的类是不可变的,因为:
现在考虑使用以下MyDate
类。
public class MyDate {
private Date; // date is not immutable
public MyDate(Date date) {
this.date = date;
}
public Date getDate() {
return date;
}
}
上面的MyDate类不是一成不变的,因为用户可以执行以下操作:
Date d = new Date(<someDate>);
MyDate md = new MyDate(d);
d.set(<someDate>); // oops, just changed value in MyDate via external reference.
也可以通过getDate()
完成。
要使MyClass
不可变,请在构造函数和getter中制作Date
的防御性副本。这些会阻止类的用户更改date
字段:
public class MyDate {
private Date; // date is not immutable
public MyDate(Date date) {
this.date = new Date(date);
}
public Date getDate() {
return new Date(date);
}
}