Java Methoden verknüpfen?
Ich habe 2 Klassen erstellt. Jetzt möchte ich in der einen Klasse die Variable "name" aus der Methode "monster1" aus der anderen Klasse ausgeben (System.out.println). Wie bekomme ich das hin?
Und kann ich das auch mit mehreren Methoden machen? Also wenn ich z.B. 20 Methoden habe und in allen die Variable "name" vorhanden ist aber jeweils einen anderen Wert hat?
4 Antworten
Du musst den Wert übergeben. Dazu muss eines der Objekte das andere kennen.
Beispiel:
class Person {
public String getName() { // example 1: pass by return value
String name = "Ted";
return name;
}
public void callName(Speaker speaker) { // example 2: pass by parameter
String name = "Ted";
speaker.say(name);
}
}
class Speaker {
public void sayName(Person person) {
System.out.println("Hello " + person.getName());
}
public void say(String word) {
System.out.println(word);
}
}
// main:
Person person = new Person();
Speaker speaker = new Speaker();
person.callName(speaker); // Ted
speaker.sayName(person); // Hello Ted
In diesen Fällen übergebe ich die jeweilige Objektreferenz via Parameter an die jeweilige Methode.
Wenn die Übergabe immer an das selbe Objekt erfolgen soll, macht es allerdings Sinn, sich dessen Referenz in einem Feld zu speichern, auf welches alle Methoden Zugriff haben. Die Referenzübergabe erfolgt diesmal über den Konstruktor, um sofort nach Objekterzeugung mit dem fremden Objekt arbeiten zu können.
Beispiel:
class Person {
private final Speaker speaker;
public Person(final Speaker speaker) {
this.speaker = speaker;
}
public void callName() {
speaker.say("Some name");
}
public void callOtherName() {
speaker.say("Other name");
}
/* ... */
}
// main:
Person person = new Person(new Speaker());
person.callName(); // Some name
person.callOtherName(); // Other name
(...) aus der Methode "monster1" (...)
Eine Methode bildet immer eine Tätigkeit ab. Das heißt, sie sollte dementsprechend auch immer ein Verb im Namen haben (Beispiele: start, doSomething, getSomething, ...), damit einem Leser an jeder Stelle, wo sie vorkommt, sofort ersichtlich wird, welchen Zweck sie erfüllt.
Also wenn ich z.B. 20 Methoden habe und in allen die Variable "name" vorhanden ist (...)
Hierzu würde ich dir den Rat geben, zu schauen, ob sich diese verschiedenen Methoden nicht in irgendeiner Form abstrahieren lassen.
Beispiel:
class MonsterManager {
/* ... */
public void callMonster1() {
speaker.say("Sullivan");
}
public void callMonster2() {
speaker.say("Randall");
}
/* etc. ... */
}
Dieser Fall könnte folgendermaßen verkürzt werden:
class MonsterManager {
private String[] monsterNames;
private final Speaker speaker;
public MonsterManager(final Speaker speaker) {
this.speaker = speaker;
monsterNames = new String[] { "Sullivan", "Randall", /* ... */ };
}
public void callMonster(int index) {
if (index > -1 && index < monsterNames.length) {
speaker.say(monsterNames[index]);
}
}
}
die Variable "name" aus der Methode "monster1"
Du kannst lokale Variablen immer nur in der Methode verwenden. Die gibt's nur innerhalb der jeweiligen Methode.
Eine Instanzvariable einer Klasse kannst du aus anderen Klassen verwenden, wenn die Sichtbarkeit entsprechend festgelegt ist.
Es gibt viele viele Möglichkeiten, das zu machen. Einige wurden dir schon genannt. Alles hat Vor- und Nachteile. Kommt darauf an, wie umfangreich dein Programm mal wird und wozu du es brauchst.
Zunächst solltest du dir eine gewisse Architektur (Struktur) für dein Programm überlegen, so dass du solche Beziehungen hinbekommst.
Hier eine grobe (etwas unvollständig ausgeführte) Möglichkeit, die sich anbietet, wenn die Daten aus einer Datenbank stammen - unter der Annahme, dass Person und Monster eine 1:n-Beziehung sind (also eine Person hat n Monster):
public class Application() {
private final Database database;
private final PersonManager personManager;
public Application(Config config) {
database = new Database(config.getDatabaseConfig());
personManager = new PersonManager(this);
monsterManager = new MonsterManager(this);
}
public void init() throws IOException {
database.init();
personManager.init();
monsterManager.init();
}
public void terminate() {
monsterManager.terminate();
personManager.terminate();
database.terminate();
}
//...getter for all three..
}
public class MonsterManager() {
private final Application application;
private final Map<Integer, Monster> monsters;
public PersonManager(Applcaton application) {
this.application = application;
}
public void init() throws IOException {
for (MonsterData data : application.getDatabase().queryAllMonsters()) {
monsters.put(data.getId(), new Monster(data, this));
}
}
public void terminate() {
monsters.clear();
}
public List<Monster> getMonstersByPersonId(int personId) {
return monsters.values().stream().filter(e -> e.getId == personId).toList();
}
}
public class Monster {
private final MonsterData data;
private final MonsterManager manager;
public Person(MonsterData data, MonsterManager manager) {
this.data = data;
this.manager = manager;
}
//...getter for all data members like .getName()...
}
public class PersonManager() {
private final Application application;
private final Map<Integer, Person> persons;
public PersonManager(Applcaton application) {
this.application = application;
}
public void init() throws IOException {
for (PersonData data : application.getDatabase().queryAllPersons()) {
persons.put(data.getId(), new Person(data, this));
}
}
public void terminate() {
persons.clear();
}
public Person getPerson(int personId) throws IOExecption {
return persons.get(persinId);
}
public List<Monster> getMonsters(int personId) {
return application.getMonsterManager().getMonstersByPersonId(personId);
}
}
public class Person {
private final PersonData data;
private final PersonManager manager;
public Person(PersonData data, PersonManager manager) {
this.data = data;
this.manager = manager;
}
//...getter for all data members like .getName()...
public List<Monsters> getMonsters() {
return manager.getMonsters(data.getId());
}
}
Für jede Art von Entities gibt es jeweils:
- eine XxxxData-Klasse (die nur die unverarbeiteten Daten aus der Datenbank enthält) (habe ich nicht aufgeführt, simples records mit den Daten halt)
- eine Xxxx-Klasse, die die Entity-Instanzen mit den einzelnen Funktions-Methoden enthält
- eine XxxxManager-Klasse, die die Daten aus der Datenbank abruft und daraus die Entities erzeugt.
und die Klasse für den Datenbankzugriff, die die Lade- und Speichermethoden enthält und entsprechend auf die Datenbank zugreift (habe ich auch weggelassen, SQL halt, falls es eine SQL-Datenbank ist)
In den Konstruktoren der Entities sollten die Daten validiert werden, also auf Gültigkeit geprüft werden (habe ich weggelassen, um das Beispiel klein zu halten). Falls ungültig: throw new IllegalArgumentException("this is invalid: bla bla");
Entweder, du lädst halt alle Person und alle Monster aus der Datenbank, wie in diesem Beispiel, oder - falls das zu viel ist - erst bei Abruf mit ggf. Caching.
Wenn man die jeweils übergeordnete Referenz im Konstruktor übergibt und speichert, kann man auf andere Teile der Application zugreifen.
Somit kannst du letztlich sagen: person.getMonsters().stream().... mach irgendwas mit den Monstern, die der Person zugeordnet sind, wie z.B. deren Namen abzufragen.
Um das ganze zu starten, muss man eine Instanz von Application erzeugen und initialisieren. Dann kann man die ganzen Sachen solange nutzen, bis das ganze über .terminate() sauber beendet wird.
Die Application bekommt wiederrum die Config im Konstruktor übergeben, wo u.a. die Zugangsdaten für die Datenbank drin sind.
Das Beispiel eignet sich für eine "echte" Anwendung, die man wirklich wirtschaftlich nutzen möchte und die vielleicht mal ganz groß wird (mit vielen vielen Managern und einer entsprechend umfangreichen Datenbank).
Wenn es sich nur um eine Schulaufgabe o.ä. handelt, vielleicht übertrieben.
Da du von Klassen und nicht von Objekten sprichst:
Mache die Variable "name" einfach "public static" und schon kannst du von beliebigen anderen Klassen auf sie zugreifen.
Dann hätte jedes Monster den selben Namen ... ob das erwünscht ist?