2016-08-16 3 views
-1

Ich habe ein Person-Objekt, das initialisiert wurde, und wenn ich die Methode wie getName anrufe, kann ich sie abrufen.Wenn ich zu ArrayList hinzufüge, fügt es die Hauptanmerkliste hinzu, nicht die Objekte

public Person(String fName, String lName, List<Role> roleList) { 
    this.firstName = fName; 
    this.lastName = lName; 
    this.roleList = new ArrayList<Role>(); 
} 

Jede Person muss eine Liste von Rollen haben, so dass ich eine Liste genannt haben roleList die ich List<Role> roleList = new ArrayList();

initialisieren zu verwenden, wenn es erstellt als

testDriver = new Person("Mike", "Joy", testRoleList); 
testDriver2 = new Person("Rich", "Johns", testRoleList); 

In meiner Berufung Klasse übergeben wird i möchte nur diesen Mitarbeitern ein Element hinzufügen testRoleList. Für diesen Test habe ich testRoleList veröffentlicht, aber ich habe einen Getter, der die testRoleList abruft;

Role roleToAdd = Role.DRIVER; 

// Only add the new role to the test driver 
testDriver.testRoleList.add(roleToAdd); 

Aber wenn man diese laufen tut es die Rolle hinzufügen, aber wenn ich versuche, die Größe der Testfahrer und testDriver2 Liste abzurufen mit:

System.out.println(testDriver.testRoleList.size()); 

System.out.println(testDriver2.testRoleList.size()); 

Die resultierende Liste Größe 1 für beide Liste obwohl ich testDriver2 keine Rolle hinzugefügt habe.

Wie kann ich nur die Rolle in dem nur Testfahrer oder einfach testDriver2

+0

Da wir nicht den komplexen Code haben (Testfahrer ist eine Person Objekt, das keinen testRoleList aber eine roleList Eigenschaft hat) Ich bin ziemlich sicher, es ist nur ein Fehler im Code ... – loicmathieu

+1

Es ist eigentlich kein Problem von Call-by-Value vs Anruf-by-Referenz. Das Problem scheint irgendwo in der Klasse "Person" zu liegen, z.B. 'roleList' ist statisch oder etw. so wie das. Außerdem initialisierst du 'roleList' im Konstruktor, aber fügst das Element zu 'testRoleList' hinzu, was eine völlig andere (und geteilte) Liste sein könnte. – Thomas

+0

Ich habe es jetzt ausprobiert, indem ich im Person-Konstruktor this.testRoleList = roleList gesagt habe, welches der Parameter ist, an den es übergeben wird. aber ich bekomme immer noch die gleiche Listengröße, die es nur zu testRoleList hinzuzufügen scheint und nicht die Eigenschaft davon innerhalb der spezifischen Person. –

Antwort

0

Die Sache ist die, dass, wenn Sie ein neues Person erstellen, die übergebene List werden mit einer frisch erstellten neuen leeren List überschreiben. Also, wenn Sie etwas auf der Liste, zum Beispiel durch hinzufügen:

testDriver.testRoleList.add(roleToAdd); 

Und danach erstellen Sie eine neue Person:

testDriver2 = new Person("Rich", "Johns", testRoleList); 

Dann wird die Liste wieder leer sein, weil Sie diesen Code in der Konstruktor:

this.roleList = new ArrayList<Role>(); 

Sie müssen genau wissen, was Ihr Code tut, es zu ändern, so dass es das tut, was Sie wollen. An dieser Stelle kann es gut sein zu sagen, dass es kein gutes Design ist, um Parameter durch Überschreiben übergeben.
Wenn Sie so etwas wie eine globale List von Rollen wollen, dann ist es nicht die Aufgabe der Klasse Person, diese List zu initialisieren. Lassen Sie eine andere Klasse diesen Job ausführen, übergeben Sie den Verweis auf die Liste wie bisher an Person, und überschreiben Sie ihn dann nicht mit einer neuen Referenz. Speichern Sie es, verwenden Sie es, fügen Sie etwas hinzu, aber erstellen Sie es nicht neu.

Aber wenn Sie möchten, dass jeder Person seine eigene List von Rollen hat, dann ist es nicht notwendig, eine Referenz von außen zu übergeben. In diesem Szenario ist es die Aufgabe der Klasse Person und nur dieser Klasse, eine solche List zu verwalten.
In diesem Fall sollten Sie die List parameter aus dem Konstruktor entfernen, aber erstellen Sie eine List als Member-Variable, dann bieten Sie einige Methoden zur Interaktion mit ihm.Hier ein Beispiel:

public final class Person { 

    private final List<Role> mRoleList; 

    public Person(final String fName, final String lName) { 
     ... 
     mRoleList = new LinkedList<>(); 
    } 

    public void addRole(final Role role) { 
     mRoleList.add(role); 
    } 

    public boolean hasRole(final Role role) { 
     return mRoleList.contains(role); 
    } 

    public List<Role> getRoles() { 
     return Collections.unmodifiableList(mRoleList); 
    } 

} 

Dann können Sie solche Dinge tun:

Role r1 = ... 
Role r2 = ... 

Person person1 = new Person("a", "a"); 
Person person2 = new Person("b", "b"); 

person1.addRole(r1); 
person1.addRole(r2); 

person2.addRole(r2); 

Und das Ergebnis ist das, was man erwarten würde, hat person1r1 und r2, person2 hat nur r2.
Als Randnotiz, vielleicht ein Set anstelle einer List spiegelt besser, was Sie wollen, dass Ihre roleList sein. Abfragen wie contain sind dann sehr schnell (O(1)), in einer List sind sie sehr langsam (O(n)).

0

In einfachen Worten, Sie beziehen sich auf das gleiche Objekt testRoleList, in Ihren beiden Objekten testDriver, testDriver2.

Beim Erstellen des Objekts Person übergeben Sie die Liste der Rollen, indem Sie für jedes Person Objekt eine Liste erstellen, die Role enthält.

Set ist besser als eine Liste aus Sicht der Leistung.

Wenn Rollen begrenzt und gut entschieden sind, können Sie EnumSet anstelle von ArrayList verwenden. Auch hier müssen Sie verschiedene EnumSet "Role" -Objekte für verschiedene Person-Objekte initialisieren.

Um Synchronisationsprobleme zu vermeiden, verwenden Sie Collections.synchronizedSet.

Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class)); 

Siehe https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html

Verwandte Themen