不知道我应该如何让这个Arraylist不被编辑

时间:2016-02-20 06:43:11

标签: java arraylist

我有这个班,Party,我有一个arraylist回复和arraylist受邀。我们的目标是,我们应该能够使用arraylists为这些addInvited()添加名称,并使用getInvited()获取该名称。我知道问题出在这两种方法之一,因为其他方法都已通过测试。我需要这样做,以便有人可以使用addInvited()添加一个Person对象,但该人不能更改他的名字。我似乎无法弄清楚我是不是制作了足够深的副本,或者是什么......

    package lab04partB;

    import java.util.ArrayList;

    public class Party {
    private ArrayList<Person>   invited;
    private ArrayList<Person>   RSVP;

    public Party() {
        invited = new ArrayList<Person>();
        RSVP = new ArrayList<Person>();
    }

    public void addInvited(Person person) {
        if (!invited.contains(person)) {
            Person JohnDoe = new Person(person.getName());
            invited.add(JohnDoe);
        }
    }

    public ArrayList<Person> getInvited() {
        ArrayList<Person> tempList = new ArrayList<Person>(invited);
        return tempList;
    }

    public void addRSVP(Person person) {
        if ((!RSVP.contains(person)) && (invited.contains(person))) {
            Person JaneDoe = new Person(person.getName());
            RSVP.add(JaneDoe);
        }
    }

    public ArrayList<Person> getRSVP() {
        ArrayList<Person> tempList = new ArrayList<Person>(RSVP);
        return tempList;
    }

    }

如果它有帮助,这是它正在运行的测试!

@Test
public void testGetInvitedModifyNamesReturned() {
    Party  party = new Party();
    Person a     = new Person( new String( KANY_GARCIA   ));
    Person b     = new Person( new String( LAURA_PAUSINI ));

    party.addInvited( a );
    party.addInvited( b );

    ArrayList<Person> list = party.getInvited();
    assertEquals( 2, list.size() );
    for (Person p : list) {
        p.setName( new String( MIGUEL_RIOS ));
    }

    list = party.getInvited();
    assertEquals( "Incorrect result", 2, list.size() );
    assertTrue  ( "Incorrect result", list.contains( a ));
    assertTrue  ( "Incorrect result", list.contains( b ));
}

3 个答案:

答案 0 :(得分:0)

一种方法是在namePerson中创建final字段,但之后任何人都无法更改任何人的姓名。猜猜那不是你想要的。

或者,您可以在Party中创建子类Person的内部类,并禁止更改名称。然后,当您将一个人添加到一方时,您首先将输入参数转换为不可变的人。

class Party {

    private static final class ImmutablePerson extends Person {

        public ImmutablePerson(String name) {
            super(name);
        }

        @Override
        void setName(String s) {
            throw new RuntimeException("Cannot change name");
            // or just do nothing here
        }

    }

    public void addInvited(Person person) {
        ImmutablePerson immutable = new ImmutablePerson(person.getName());
        if (!invited.contains(immutable)) {
            invited.add(immutable);
        }
    }

}

答案 1 :(得分:0)

制作Person immutable。这实际上也是最佳实践,因为人们不会更改数据,并且(如此处)您可以安全地发布它们。

答案 2 :(得分:0)

有几种方法可以做到这一点......

您可以使用接口来维护API的合同期望,因此您可以设置Person(带有getter)和可变版本(带有setter)的非可变版本,这意味着您的{{ 1}} class可以返回非可变类型,阻止人们直接修改值。

这可能导致使用非可变实例作为可变版本的包装器,进一步阻止人们投射结果来解决这个问题。

像...一样的东西。

Party

然后你的public interface Person extends Comparable<Person> { public String getName(); } public class DefaultPerson implements Person { private String name; public DefaultPerson(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Person)) { return false; } final Person other = (Person) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } return true; } @Override public int hashCode() { int hash = 3; hash = 37 * hash + Objects.hashCode(this.name); return hash; } @Override public int compareTo(Person arg0) { return arg0.getName().compareTo(name) * -1; } public Character[] toCharacterArray(String s) { if (s == null) { return null; } int len = s.length(); Character[] array = new Character[len]; for (int i = 0; i < len; i++) { array[i] = new Character(s.charAt(i)); } return array; } @Override public String toString() { return getName(); } } 可能看起来像......

Party

该类只知道处理public static class Party { private ArrayList<Person> invited; private ArrayList<Person> RSVP; public Party() { invited = new ArrayList<Person>(); RSVP = new ArrayList<Person>(); } public void addInvited(Person person) { if (!invited.contains(person)) { invited.add(person); } } public List<Person> getInvited() { return Collections.unmodifiableList(invited); } public void addRSVP(Person person) { if ((!RSVP.contains(person)) && (invited.contains(person))) { RSVP.add(person); } } public List<Person> getRSVP() { return Collections.unmodifiableList(RSVP); } } 类型,这些类型不可变(好吧,您可以创建Person的实例并将它们添加到列表中,这会阻止调用者修改名称,但这取决于你)

该类还使用DefaultPerson来阻止调用者修改Collections.unmodifiableList!奖金:)

这意味着,做一些像......

List

是不可能的,因为List<Person> list = party.getInvited(); for (Person p : list) { p.setName(new String("Whelma")); } 不是setName的方法!

但是...

这可能超出了您的作业范围,相反,当您返回被邀请者列表时,您可以创建值的新实例,例如......

Person

这不是最佳选择,但它允许您的代码通过您拥有的测试。

我还应该指出,public void addInvited(Person person) { if (!invited.contains(person)) { invited.add(person); } } public ArrayList<Person> getInvited() { ArrayList<Person> tempList = new ArrayList<>(invited.size()); for (Person p : invited) { tempList.add(new Person(p.getName())); } return tempList; } 与来自JavaDocsequals有合同关系:

  

请注意,通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相同的哈希代码。

基本上,这意味着,如果你覆盖hashcode,你还必须覆盖equals(反之亦然)