Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Klassenübergreifende Ausgabe mittels "getter" nicht möglich
ich hab folgendes Problem. Will, dass in der main-Methode die Farbe Weiß ausgegeben wird, allerdings bekomme ich das nicht hin.
Aus diversen Tutorials weiß ich, dass ich die Objekte und den getter nicht mit static deklarieren muss, aber die IDE gibt als Fehler; Error: non-static method ausgabe() cannot be referenced from a static context
[CODE lang="java" title="nichtMain"]public class nichtMain {
private String farbe = "Weiß";
public String getFarbe() {
return this.farbe;
}
}
[/CODE]
[CODE lang="java" title="Die Main"]
public class dieMain extends nichtMain {
public static void main(String[] args) {
ausgabe();
}
public void ausgabe (){
System.out.println(getFarbe());
}
}
[/CODE]
Nicht statische Methoden sind immer Instanz gebunden. Statische Methoden nicht. Deswegen kannst du in statischen Methoden nicht ohne eine Referenz eine Instanz Methode aufrufen. Also brauchst du in der main Methode, die ja statisch ist, eine Refferenz vom Typ der Klasse, derer Methode du aufrufen möchtest.
Java:
public static void main(String[] args) {
dieMain a = new dieMain();
a.ausgabe();
}
Du solltest Klassen Namen übrigens immer groß schreiben.
Nur so als Hinweis: Vererbung ist nahezu immer das falsche. Mit dieMain extends nichtMain sagst du aktuell "die Main ist nicht [die] Main", da sollte offensichtlich sein, dass es Unsinn ist
Aus diversen Tutorials weiß ich, dass ich die Objekte und den getter nicht mit static deklarieren muss, aber die IDE gibt als Fehler; Error: non-static method ausgabe() cannot be referenced from a static context
Arbeitest du ein Buch durch oder auf eigene Faust?
Ich würde ja ersteres empfehlen, z.B. "Java von Kopf bis Fuß". Schau es dir allerdings vorher mal an, manche kommen mit der Art nicht klar. Tutorials sind so eine Sache. Da muss man erst mal ein gutes finden, das einen keinen Schmarrn beibringt.
Aber um kurz auf dein Problem mit der Fehlermeldung einzugehen:
Java:
class Foo {
static int klassenVariable;
int instanzVariable;
static void printKlassenVariable() {
System.out.println(klassenVariable);
}
void printInstanzVariable() {
System.out.println(instanzVariable);
}
public static void main(String[] args) {
// Zugriff auf die Klassenvariable erfolgt i.d.R. über den Klassennamen
Foo.klassenVariable = 42;
// gleiches gilt für die Methode
Foo.printKlassenVariable(); // 42
// Zugriff auf die Instanzvariable erfolgt über eine Instanz der Klasse
Foo foo1 = new Foo();
foo1.instanzVariable = 21;
foo1.printInstanzVariable(); // 21
foo1.printKlassenVariable(); // 42
// es kann auch mehrere Instanzen geben
Foo foo2 = new Foo();
foo2.instanzVariable = 22;
foo2.printInstanzVariable(); // 22
foo2.printKlassenVariable(); // 42
}
}
Du benötigst also eine Instanz der Klasse, um auf nicht-statische Methoden/Variablen zugreifen zu können und genau das sagt die Meldung aus.
Die Regel sollte sein: Das einzige "static" steht an der main() Methode!
Bemerke auch: Die Instanzvariable hat für jede erzeugte Instanz einen eigenen Wert, während die Klassenvariable über alle Instanzen den selben Wert hat (es gibt die Klasse ja nur einmal). Du kannst in jeder erzeugten Instanz auf den Wert der Klassenvariablen zugreifen, aber der zugewiesene Wert wird für alle Instanzen der selbe sein.
Nur als Beispiel wofür man das brauchen könnte. Nehmen wir an du möchtest, dass jede Instanz eine Identifikationsnummer erhält, die sich automatisch erhöht, wenn eine neue Instanz erzeugt wird:
Java:
class SelfCountingClass {
private static int next = 0; // "next" hat in allen Instanzen den selben Wert, weil "static"
private int id;
// Konstruktor der Klasse
public SelfCountingClass() {
id = next; // der Instanzvariablen die nächste Id zuweisen
next++; // und für die nächste Id um eins erhöhen
}
public int getId() {
return id;
}
}
SelfCountingClass scc0 = new SelfCountingClass();
SelfCountingClass scc1 = new SelfCountingClass();
SelfCountingClass scc2 = new SelfCountingClass();
System.out.println(scc0.getId()); // 0
System.out.println(scc1.getId()); // 1
System.out.println(scc2.getId()); // 2
In meinem Fall, kann ich nur mittels Vererbung "extends" auf eine andere Klasse zugreifen. Sofern ich nicht die Vererbung verwende, dann wird mir in der IDE IntelliJ der Code "getFarbe()" rot markiert (welches sich ja nicht in der main, sondern in einer anderen Klasse befindet). Die main Klasse kann das "getFarbe()" nicht finden bzw. nicht aufrufen. Das ist der Grund, weßhalb ich ständig mit Vererbung arbeite.
@ DrPils:
Ich habe die Änderungen soweit ausgeführt und folgendes eingefügt:
Java:
dieMain a = new dieMain();
Allerdings funktioniert die klassenübergreifende Ausgabe der Farbe immer noch nicht.
Klassenübergreifend funktioniert es bei mir immer noch nicht:
[CODE lang="java" title="main-Klasse" highlight="4"]public class dieMain {
public static void main(String[] args) {
dieMain a = new dieMain();
a.ausgabe();
}
public void ausgabe (){
System.out.println(getFarbe());
}
}[/CODE]
[CODE lang="java" title="andere Klasse"]public class nichtMain {
private String farbe = "Weiß";
public String getFarbe() {
return this.farbe;
}
}[/CODE]
Ohne Vererbung funktioniert es einfach nicht. IntelliJ hebt "getFarbe()" rot hervor, es durchsucht andere Klassen nicht. Als Fehlermeldung erhalte ich:
Error: ( 9, 28 ) java: cannot find symbol
symbol: method getFarbe()
location: class dieMain
Das sollte aber nicht der Grund für Vererbung sein. Vererbung ist immer eine "ist ein"-Beziehung, z.B. Katze ist ein Tier => class Katze extends Tier. Und Vererbung sollte mit Bedacht eingesetzt werden, besser ist in der Regel Komposition, aber das führt jetzt zu weit an dieser Stelle.
Schreib doch mal, was du genau erreichen willst! Einfach auf eine Methode einer anderen Klasse zugreifen? Dazu muss nichts vererbt werden.
Java:
public class Foo {
private String farbe = "grün";
public String getFarbe() {
return farbe;
}
}
public class Main {
public static void main(String[] args) {
Foo foo = new Foo(); // erstelle eine Instanz der Klasse
System.out.println(foo.getFarbe()); // und greife auf deren Instanzmethode zu
}
}
In deinem Code erstellst du zwar eine Instanz von "dieMain", damit kannst du dann auf deren Instanzmethode ausgabe() zugreifen.
Du müsstest aber eine Instanz von "nichtMain" erstellen, um auf deren Instanzmethoden zugreifen zu können.
Falls die Ausgabe in der Methode ausgabe() geschehen soll, dann kannst du entweder einen Parameter verwenden oder die Instanz von "nichtMain" in der Methode ausgabe() erzeugen. Gibt aber noch weitere Möglichkeiten.
Java:
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.ausgabe1(); // Möglichkeit 1
Foo foo = new Foo();
main.ausgabe2(foo.getFarbe()); // Möglichkeit 2
main.ausgabe3(foo); // Möglichkeit 3
}
public void ausgabe1() {
Foo foo = new Foo();
System.out.println(foo.getFarbe());
}
public void ausgabe2(String s) {
System.out.println(s);
}
public void ausgabe3(Foo foo) {
System.out.println(foo.getFarbe());
}
}
Ich stelle mir das immer gerne richtig vor. (Diesbezüglich empfand ich das Buch "Object thinking" aus dem MS Press Verlag sehr gut und interessant.)
Eine Klasse ist dann nur ein Bauplan. Auf dem ist in der Regel nicht mehr als der Bauplan. Aber klar: Man kann da auch drauf rum kritzeln und Dinge anheften: Wenn Du wissen willst, wie viele Objekte von dem Bauplan schon gebaut wurden, dann machst Du halt eine Strichliste oder so auf dem Bauplan.
Ansonsten interessiert dich der Bauplan später doch einfach nicht. Damit willst Du nichts zu tun haben. Ich will später ein Skodia Octavia vor der Tür haben. Und dazu will ich Fahrzeugschein und Fahrzeugbrief und die Schlüssel. Der Bauplan interessiert mich nicht (in der Anwendung). Natürlich: Die Entwickler bei Skoda haben einen Bauplan und da ist der extrem wichtig. Aber für mich später ist er uninteressant, denn ich will ja ein Auto und wenn ich damit fahre, dann will ich ein AutoMitSchaltgetriebe fahren...
Und genau so muss es in Deinem Programm auch sein. Das hilft dann auch bei der Findung der Klassen und wo was an Code hinein gehört. Denn wenn man sich etwas so vorstellt, dann gibt es logische Trennlinien. Und die kann man dann auch weiter entwickeln.
Dazu ist es aber existenziell, dass Klassen alles Nomen sind bzw. enthalten / ausdrücken. Daher sind die auch immer am Anfang gross geschrieben.
dieMain ist also blöd. Was ist denn da in der Klasse drin? In Deinem Fall ist es der Startpunkt. Oder was für Begriffe fallen dir da ein?
Und was ist / macht nichtMain? Das ist irgendwas mit Farben? Man sieht noch nicht viel an Funktionalität, aber Farbe könnte passen. Und dann die Ausgabe: Da druckst Du diese, also print oder druckeAus.
Somit haben wir dann jetzt schon folgende zwei Klassen:
Java:
public class Startpunkt {
public static void main(String[] args] {
}
}
Java:
public class Farbe {
public void druckeAus() {
System.out.println("Eine Farbe");
}
}
Nun wollen wir drucke ausführen. Wenn ich eine Autotür öffnen will: Dazu brauche ich ein Auto. Also um dieses drucke auszuführen, brauchen wir eine Farbe.
Dazu müssen wir uns also eine Instanz erzeugen und die können wir dann drucken:
Java:
public class Startpunkt {
public static void main(String[] args] {
Farbe eineFarbe = new Farbe();
eineFarbe.druckeAus();
}
}
Ich selbst tendiere dazu, das immer mit Englischen Begriffen zu nutzen. Dann ist die Klasse Startpunkt oft die Klasse Main. Farbe wäre Color. drucke wäre print. Aber das ist egal - das sind nur freie Bezeichner. Wichtig ist lediglich, dass diese deutlich erkennbar sind.
Das Ergebnis ist dann auch ein einfach lesbarer Code: eineFarbe.druckeAus(); - da ist deutlich, was da passiert.
(Wobei es auch ein Problem aufzeigt: druckeAus funktioniert nicht - beim Aufruf kommt auf meinem Drucker nichts raus ... Aber da kommen wir zu einem ganz anderen Problem: Wir vermischen hier Dinge. Eine Farbe hat nichts auszugeben. Das hat also eine Darstellung als Zeichenkette (toString - hier wird deutlich, wieso man alles auf Englisch machen sollte. Einiges ist halt schon Englisch!). Aber bezüglich der Ausgabe hat die Farbe doch gar kein Wissen! Das kann auf dem Ausgabestream erfolgen (System.out), in einer GUI oder einem Drucker oder oder oder ...
==> Das gehört da also nicht rein!
Somit wird daraus:
Java:
public class Farbe {
public String toString() {
return "Eine Farbe";
}
}
Java:
public class Startpunkt {
public static void main(String[] args] {
Farbe eineFarbe = new Farbe();
System.out.println(eineFarbe.toString());
}
}
Das einfach einmal als Erläuterung / Beschreibung von mir.
Wichtig also:
a) Benenne Dinge richtig.
b) Damit das klappt, musst Du Dir die "Dinge" richtig vorstellen. Dazu gehört auch, dass der Startpunkt keine Farbe ist. Also keine Vererbung!
Und dann folgt nur daraus, dass Du dann immer schauen musst / kannst, wo was hinein gehört.
ich danke euch herzlich, dass ihr euch alle viel Zeit nehmt mit das alles zu beschreiben.
Allerdings eine Bitte. Ich würde gerne wissen, wieso die klassenübergreifende Ausgabe mittels getter nicht funktioniert. Hier ist wichtig, dass
a) klassenübergreifend und
b) Einsatz von Getter (wegen private Deklaration)
Ich habe ja schon gezeigt, dass ich die Aufgabe nur teilweise lösen kann
a) mittels Einsatz von Vererbung (aber das ist ja nicht sinnvoll)
b) mittels Dekrarierung der Variablen mit Static
c) alles in eine Klasse schreiben (das funktiobiert)
Aber was nicht funktioniert ist, (wie der Titel schon sagt), die klassenübergreifende Ausgabe mittels Getter.
Das ist eigentlich das Problem an dem ich seit vielen Stunden sitze und keine Lösung finde.
Hier mal zwei Beispiele (ich benenne die Klassen ausnahmsweise mal anders):
In dem Beispiel hier habe ich den gesamten Code in einer einzigen Klasse und IntelliJ gibt mir keinen Fehler aus, sonders das Programm funktioniert.
Java:
public class Startpunkt {
public static void main(String[] args) {
Startpunkt a = new Startpunkt();
a.ausgabe();
}
public void ausgabe (){
System.out.println(getFarbe());
}
private String farbe = "Weiß";
public String getFarbe() {
return this.farbe;
}
}
Mir ist klar, dass ich keine getter verwenden muss, aber dennoch funktioniert es.
Das Problem an dem ich seit mehreren Stunden sitze und nicht lösen kann ist aber ein ganz anderes, nämlich, dass ich Klassenübergreifend und unter Verwendung von Getter immer nur Fehlermeldung in IntelliJ erhalte.
In dem Beispiel hier habe ich den gesamten Code aus zwei Klassen verteilt und möchte mittels Getter die privat deklarierten werte in der Startpunkt-Klasse ausgeben.
Java:
public class Startpunkt {
public static void main(String[] args) {
Startpunkt a = new Startpunkt();
a.ausgabe();
}
public void ausgabe (){
System.out.println(getFarbe());
}
}
Java:
public class Farbe{
private String farbe = "Weiß";
public String getFarbe() {
return this.farbe;
}
}
Wie bereits beschrieben, der Code funktioniert wenn ich alles in eine einzige Klasse schreibe. Aber warum kann meine IDE nicht klassenübergreifend etwas mittels Getter auslesen?
Weil die Methode getFarbe() nicht zur Klasse Startpunkt gehört (wie in dem ersten Code, wo alles in einer Klasse ist), sondern zur Klasse Farbe. Steht aber alles oben in #7, mit Beispielen in verschiedenen Varianten. Such dir eine aus!
Du benötigst also einfach eine Instanz der Klasse Farbe.
Java:
Farbe farbe = new Farbe();
farbe.getFarbe();
Wie @kneitzel oben geschrieben hat, ist die Klasse eine Art von Bauplan. Darin legst du u.a. fest, welche Variablen und Methoden eine Klasse, bzw. Instanzen der Klasse haben.
Java:
class Foo {
void eineMethode(){
}
}
class Bar {
void eineAndereMethode() {
}
}
Foo foo; // hier wird festgelegt, dass die Variable foo vom Typ Foo ist
foo = new Foo(); // eine Instanz von Foo erzeugen und zuweisen
foo.eineMethode(); // funktioniert
foo.eineAndereMethode(); // FEHLER!!! Foo hat keine Methode mit diesem Namen
Bar bar = new Bar(); // wie oben, nur Bar
bar.eineMethode(); // FEHLER!!! Bar hat keine Methode mit diesem Namen
bar.eineAndereMethode(); // funktioniert
So wie ich dich verstanden habe muss ich die Methode getFarbe() von Startpunkt entfernen und in die Klasse Farbe einfügen. Habe ich jetzt ausprobiert und es funktioniert immer noch nicht.
Ich wäre wünschenswert gewesen einfach eine Lösung zu erhalten, an der ich mich dann orientieren hätte können.
Chinesische Smartphone-Hersteller schaffen es schließlich auch gute Smartphones herzustellen durch Abgucken von Bauplänen (bzw. Musterlösungen) anderer Hersteller.
Hätten die nur hochqualifizierte aber unerfahrene Ingenieure gehabt, hätte die Entwicklung zwei Jahrzehnte gebraucht.
Ich verstehe nicht, wieso hier grundsätzlich nicht die Lösung gezeigt wird, an der man sich hätte orientieren können.
Die viele Erklärung nützt mir nichts. Ich kenne Begriffe wie "Instanz", "Klassenmethode" und "static" nicht.
P.S. Java eignet sich als Einsteiger-Programmiersprache nicht. Verstehe auch nicht, wieso Hochschulen und Universitäten immer noch Java lehren.
Du hättest nur die angebotene Lösung abschreiben und deine Klassennamen dafür einsetzen müssen. Das kann man hinkriegen, wenn man das Prinzip verstanden hat.
In der Klasse Startpunkt wird die Methode aufgerufen. Und zwar auf eine Instanz der Klasse Farbe. Deklariert ist sie in der Klasse Farbe. Du musst da nichts einfügen. Das steht ja alles schon korrekt in deinem Code.
Chinesische Smartphone-Hersteller schaffen es schließlich auch gute Smartphones herzustellen durch Abgucken von Bauplänen (bzw. Musterlösungen) anderer Hersteller.
Es hat doch keinen Sinn, eine fertige Lösung anzuschauen, wenn man es grundsätzlich nicht versteht.
Schau dir die Lösung aus #7 an und verstehe sie! Das entspricht genau dem, was du versuchst. Wenn du es nicht vestehst, dann frage, was du genau nicht verstehst.
Doch schon. Ist eigentlich in jeder objektorientierten Programmiersprache ungefähr ähnlich, mit kleinen Syntaxunterschieden.
Wenn du nicht verstehst, was du versuchst, dann deutet das darauf hin, dass du bereits vorher etwas nicht richtig verstanden hast. In dem Fall solltest du in deinem Buch einfach wieder ein Kapitel zurück gehen. Für konkrete Verständnisfragen ist dieses Forum auch sehr gut geeignet.
Da fehlt mir jetzt jedes Verständnis. Ich habe Dir doch auch Code gegeben in #9, welches das genau zeigt.
Daher verstehe ich gerade nicht, was Dir fehlt, denn die Lösungen hast du ja vorgesetzt bekommen. Ebenso Erläuterungen zu dem wieso und warum.
Und du machst gerade ein Hochschulstudium? Dann solltest Du eigentlich so selbständig sein, Dir gewisse Dinge zu erarbeiten. Und dazu gehören gewisse Grundlagen, also auch, was eine Instanz ist oder Klassenmethode ... Egal, was für eine Programmiersprache du lernen möchtest: diese Grundlagen hast du überall. Das will ich aber nicht weiter Thematisieren, denn die Fragestellung läuft sonst schnell auf andere Punkte hinaus ...
ich habe jetzt (außerhalb des Forums) um Hilfe gebeten.
Hier die Lösung nach der ich seit Stunden gesucht habe.
Java:
public class Startpunkt {
public static void main(String[] args) {
Startpunkt a = new Startpunkt();
a.ausgabe();
}
public void ausgabe (){
System.out.println(Farbe.getFarbe());
}
}
Java:
public class Farbe {
private static String farbe = "Weiß";
public static String getFarbe() {
return farbe;
}
}
Mittels diesem Code ist die klassenübergreifende Ausgabe mittels getter (siehe Titel) möglich.
Ich verstehe einfach nicht, wieso man mir hier im Forum meinen Code (welcher nicht funktionierte) nicht verändern wollte, sodass dieser funktioniert.
Trotzdem vielen Dank, dass ihr euch die Zeit genommen habt mir das alles ausführlich zu erklären. Anhand der Musterlösung und eurer Erklärung werde ich jetzt versuchen es zu verstehen.
Weil man in diesem Forum in der Regel versucht, dem Fragensteller soweit zu helfen, dass er versteht, was er tut und das Problem sich dadurch von selbst löst. Wie schon oben geschrieben, steht der Code, der dir hilft hier in diesem Thema. Und zwar ohne "static" mißbrauchen zu müssen.
Ohne Worte. Aber es ist toll, dass du so gute und kompetente Hilfe gefunden hast.... Da wünsche ich dir einfach noch viel Glück bei Deinem weiteren Hochschulstudium- hoffe, dass du es packst, obwohl die Hochschule so komplizierte Dinge wie Java verwendet. (So du es nicht schaffen solltest, musst Du Dir aber keine Gedanken machen, denn es liegt ganz klar an der Hochschule und nicht an Dir und Deiner Herangehensweise... )
Den kompletten Code in eine einzige Klasse zusammenzufügen hat immer funktioniert.
Meine Herausforderung war, dass Inhalte aus der Klasse "Farbe" in die Klasse "Startpunkt" übertragen werden.
Sorry, bei allen Beiträgen konnte ich nirgendwo erkennen wo auf mein Problem der klassenübergreifenden Ausgabe eingegangen wurde.
Den kompletten Code in eine einzige Klasse zusammenzufügen hat immer funktioniert.
Meine Herausforderung war, dass Inhalte aus der Klasse "Farbe" in die Klasse "Startpunkt" übertragen werden.
Sorry, bei allen Beiträgen konnte ich nirgendwo erkennen wo auf mein Problem der klassenübergreifenden Ausgabe eingegangen wurde.
Den kompletten Code in eine Klasse zu stecken macht ebenso wenig Sinn wie einfach nur Code in eine zweite Klasse zu verschieben. Sinnvoll wäre es, sich erst einmal ein objektorientiertes Design zu überlegen.
Aber wenn Du nun eine Klasse Farbe hast, dann kannst Du dir davon eine Instanz erzeugen. Das hast Du dann auch im letzten Code gemacht: Farbe white = new Farbe();
Im dann folgenden Aufruf hast Du dann aber wieder nur den Klassennamen und das übersetzt nicht: System.out.println(Farbe.getFarbe());
Und da kopiere ich einfach einmal aus meiner Erläuterung den Code, der es richtig zeigt:
Java:
Farbe eineFarbe = new Farbe();
System.out.println(eineFarbe.toString());
Jetzt muss man nur noch "white"/"eineFarbe" und das "getFarbe()"/"toString()" tauschen und du siehst, wie Dein Code übersetzen würde ...
Du erkennst also, dass die Beispiele, die wir gebracht haben, das alles schon gemacht haben. Incl. Erläuterung. Und wenn man da etwas nicht versteht oder Worte nicht kennt: Fragen. (Oder besser: Einfach mal selbst danach suchen! Eigenständig lernen ...)