Lösen einer C Aufgabe in Java

Status
Für weitere Antworten geschlossen.

yxy

Lieutenant
Registriert
Juli 2014
Beiträge
552
Unbenannt.PNG

Hallo, ich habe obere Aufgabe gegeben.
Die Aufgabe ist für C gestellt, würde sie aber gerne in Java lösen.

Ich hätte das Ganze jetzt mittels einer Klasse gelößt.
Das würde dann ja eher Teilaufgabe 2 entsprechen.
(Verbesserung: getter und setter anstelle der public Members, aber sei mal dahingestellt)

Wie würdet Ihr Teilaufgabe 1 in Java lösen?
Kann ich irgendwie die Referenz der Ergebnisse xr_1 und xr_2 übergeben, oder gibt es in Java nur die Möglichkeit über eine Klasse zu gehen?


Code:
package Feb_2014_A2;

public class MainClass {
    public static void main (String[] args){
        Root_coordinates calculationA = new Root_coordinates(1,1,1);
 
        System.out.println(calculationA);
    }
}

Code:
package Feb_2014_A2;

public class Root_coordinates {

    //Objekteigenschaften
    private int a;
    private int b;
    private int c;
    private int partValue;

    public float xr_1;
    public float xr_2;
    public int numberResults;

    //Konstruktor
    public Root_coordinates(int a_, int b_, int c_) {
        a = a_;
        b = b_;
        c = c_;
        calcRoots();
    }

    //Methode
    private void calcRoots() {
        partValue = b * b - 4 * a * c;

        if (partValue > 0) {
            xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            xr_2 = (float) (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            numberResults = 2;
        }
        if (partValue < 0) {
            numberResults = 1;
        }
        if (partValue == 0) {
            xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            numberResults = 1;
        }
    }

    @Override public String toString() {
        //calcRoots();
        if (numberResults == 2) {
            return "Zwei Lösungen:" + xr_1 + "\t" + xr_2;
        }
        if (numberResults == 1) {
            return "Eine Lösung:" + xr_1;

        } else {
            return "Keine Lösung";
        }
    }

}
 

Anhänge

  • Unbenannt.PNG
    Unbenannt.PNG
    85,6 KB · Aufrufe: 454
zu 2.1 wenn ich mich nicht irre arbeitet java bei primitiven daten typen (int, double, char, ...) immer mit call by value
und bei objekten mit call by reference

also um aus den primitiven int ein objekt zu machen müsstest du dir deine eigene klasse schreiben die ein int hält

Code:
public class intCallByReference{
    int val;
}

und wenn du jetzt intCallByReference einer funktion übergibst geschieht dieses via call by reference


//EDIT:: ich sehe gerade auf diese idee bist du auch schon gekommen, sorry für den unnötigen kommentar :D
 
Zuletzt bearbeitet:
Unter Java lässt sich die Aufgabe grundsätzlich nicht wie gefordert mittels Call-by-Reference realisieren, da Java beim Aufruf/Übergeben immer Call-by-Value verwendet.;)

masterholdy schrieb:
und bei objekten mit call by reference
Auch bei Objekten arbeitet Java mit Call-by-Value, wobei der "Value" eine Referenz ist. Ist aber immer noch was anderes als Call-by-Referenz.
 
Zuletzt bearbeitet:
Der Code sieht doch ganz gut aus. Ob man das wirklich mit einer Klasse löst, oder eher (ähnlich zu C) einfach mit einer static Funktion, ist zum einen Geschmackssache und hängt natürlich auch vom Anwendungsfall ab.

Code:
class CalcUtil {
  public static MeinLoesungsObjekt calcRoots(int a, int b, int c) {
    // ...
  }
}

Grundsätzlich finde ich die Klasse in dem Fall etwas "zu viel", weil du mit den Werten nichts machst und sie nur einmalig in der Klasse gespeichert werden.

Wohin willst du "xr_1" und "xr_2" übergeben?
 
G00fY schrieb:
...
Auch bei Objekten arbeitet Java mit Call-by-Value, wobei der "Value" eine Referenz ist. Ist aber immer noch was anderes als Call-by-Referenz.

Yep, siehe auch: Link
Da ist das ganze recht gut erklärt
 
Code:
public Root_coordinates(int a_, int b_, int c_) {
        a = a_;
        b = b_;
        c = c_;
        calcRoots();
    }

im constructor sollte man immer den this-operator benutzen.

Code:
public Root_coordinates(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
        calcRoots();
    }
 
Hmm, ich sehe bei deinem Code mehrere Probleme:

1) Warum überhaupt eine Klasse? Was ist deine Motivation eine Klasse zu verwenden und nicht eine einfache statische Funktion?

2) Der Konstruktor wird nur beim Erstellen der Klasse aufgerufen (und somit auch calcRoot()). Das Ergebnis wird dann in den Attributen gespeichert (xr1,xr2 etc.). Wenn du die Werte (a,b etc.) im nachhinein änderst, stimmt das gespeicherte Ergebnis nicht mehr mit den Werten überein.

3) Warum überhaupt das Ergebnis überhaupt schon beim Konstruieren der Klasse berechnen und nicht calcRoot() als eine public method definieren, die dir das Ergebnis berechnet und zurückliefer, wenn du es auch brauchst?

4.) Bei Java gibt es keine Referenzen/Pointer (siehe 2.2.9 No More Pointers - http://www.oracle.com/technetwork/java/javase/simple-142616.html; bze. die ganze Seite ist interessant falls man paar Unterschiede C/C++/Java aufschnappen will)

Ich habe das Gefühl, dass du vor allem noch Schwierigkeiten mit OOP hast und würde hier noch etwas nachholbedarf sehen (Wann verwende ich überhaupt Klassen, Objekte; Welche Eigenschaften sollten sie idealerweise aufweisen etc.). Wäre aber verständlich, falls du ursprünglich aus dem C-Lager kommst :)
 
Also Java arbeitet definitiv mit Referenzen, nur ist jede Übergabe call by value. Oder wie wird sonst ein Objekt in Java referenziert?

Oder verstehe ich meinen Vorposten falsch?
 
Java arbeitet mit Referenzen, aber diese werden by value übergeben. Heißt in der Praxis: Wenn du ein Objekt an eine Methode übergibst, dann greift diese Methode auf dasselbe Objekt zu, nicht auf eine Kopie (wie bei reinem call-by-value). Alle Änderungen, die während der Methode am Zustand des Objekts vorgenommen werden, sind auf der aufrufenden Ebene sichtbar. Nicht möglich ist allerdings, das Objekt gegen ein anderes auszutauschen - bei echtem call-by-reference ginge das.

Code:
void doStuff(Foo foo) {
    foo.bar += 1;

    foo = new Foo();
    foo.bar = 42;
}

void test() {
    Foo myFoo = new Foo();
    myFoo.bar = 1;
    doStuff(myFoo);
    System.out.println(myFoo.bar);  // Ausgabe: 2
}
 
Zuletzt bearbeitet:
Danke für eure Antworten

Warum überhaupt eine Klasse?
In Teilaufgabe 2 wird eine Struktur verlangt. Das es das in Java nicht gibt, dachte ich ich schreibe dafür eine Klasse.
Du hättest das so geschrieben?:

Code:
package Feb_2014_A2;

public class OhneSeparateKlasse {

    private static float xr_1;
    private static float xr_2;
    private static int numberResults;

    public static void main(String[] args) {
        calcRoots(4, 7, 1);

        if (numberResults == 2) {
            System.out.println("Zwei Lösungen:" + xr_1 + "\t" + xr_2);
        }
        if (numberResults == 1) {
            System.out.println("Eine Lösung:" + xr_1);
        } 
        if (numberResults == 0) {
            System.out.println("Keine Lösung");
        }
    }
      
    private static void calcRoots(int a, int b, int c) {
        int partValue = b * b - 4 * a * c;

        if (partValue > 0) {
            xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            xr_2 = (float) (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            numberResults = 2;
        }
        if (partValue < 0) {
            numberResults = 0;
        }
        if (partValue == 0) {
            xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            numberResults = 1;
        }
    }
}
 
yxy schrieb:
In Teilaufgabe 2 wird eine Struktur verlangt. Das es das in Java nicht gibt, dachte ich ich schreibe dafür eine Klasse.
Klassen sind ja im Grunde das, was bei C structs sind.
Nur hat man dqa eben nicht nur die Datenstruktur, sondern fast darin auch alle Funktionen zusammen, die auf dieser Struktur irgendwas machen.

Statt also wie in C ne Funktion aufzurufen und als Parameter ein struct zu übergeben, ruft man ne sogenannte Methode (quasi eine Funktion, die den struct-Parameter implizit hat) der Klasse bzw. des Objektes auf.

Noch kurz zu den Begriffen Klasse und Objekt. Eine Klasse ist sozusagen die Definition des "structs". Welche Typen haben die Variablen der Struktur. Während ein Objekt dann sozusagen ein mit Werten belegtes struct ist. Sozusagen ein Exemplar von dem struct.
 
benneque schrieb:
Wohin willst du "xr_1" und "xr_2" übergeben?

Eine Methode kann ja immer nur eine Variable zurückgeben. Wenn ich es also nicht so wie oben mit Member der Klasse löse, kann ich der Methode main von der Methode calcRoots nur einen Wert zurückgeben.
(In einem Array die Werte speichern und dann die Referenz zurückgeben geht nicht, da die Werte ja andere Datentypen sind).
Ich müsste dann eine Klasse erzeugen mit den Variablen Lösung1, Lösung2, AnzahlLösugen und davon dann in der Methode calcRoots ein neues Objekt mit den Zuweisungen erzeugen. Auf das Objekt könnte ich dann von der Main-Methode aus zugreifen. ?
Ergänzung ()

andy_m4 schrieb:
Klassen sind ja im Grunde das, was bei C structs sind.
Nur hat man dqa eben nicht nur die Datenstruktur, sondern fast darin auch alle Funktionen zusammen, die auf dieser Struktur irgendwas machen.

Statt also wie in C ne Funktion aufzurufen und als Parameter ein struct zu übergeben, ruft man ne sogenannte Methode (quasi eine Funktion, die den struct-Parameter implizit hat) der Klasse bzw. des Objektes auf.

Noch kurz zu den Begriffen Klasse und Objekt. Eine Klasse ist sozusagen die Definition des "structs". Welche Typen haben die Variablen der Struktur. Während ein Objekt dann sozusagen ein mit Werten belegtes struct ist. Sozusagen ein Exemplar von dem struct.

Ja, und das habe ich doch ganz oben gemacht, oder nicht?
 
yxy schrieb:
In Teilaufgabe 2 wird eine Struktur verlangt. Das es das in Java nicht gibt, dachte ich ich schreibe dafür eine Klasse.

Wenn du dich möglichst eng an die C-Vorlage halten willst, dann benutz die Klasse als reinen Daten-Container, also etwa so:

Code:
class Roots
{
    public float xr_1;
    public float xr_2;
    public int numberResults;
}

Nebenbei bemerkt: In der Originalaufgabe gehören die Bedingungen "benutze call by reference" und "benutze einen Struct" zu zwei verschiedenen Teilaufgaben. Es soll also nicht beides kombiniert werden. Das Ziel der Aufgabe ist offenbar, verschiedene Möglichkeiten aufzuzeigen, wie du aus einer Funktion mehrere Werte zurückgeben kannst. In Java ist eindeutig der zweite Weg - Rückgabe eines Objekts (da es keine Structs gibt) - üblich.
 
In Java gibt's zwar keine structs, aber ein POJO bzw. JavaBean entspricht dem zu 99%.
Also einfach ausschließlich private Properties benutzen und zu jedem Property einen public getter und public setter hinzufügen und das wars.

Code:
public class MyBean {

    private String someProperty;

    public String getSomeProperty() {
         return someProperty;
    }

    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
}

Die meisten IDEs generieren dir die Getter und Setter automatisch auf Knopfdruck.
 
So wäre es dann 1:1 zu Strukturen in C, richtig?

Code:
package Feb_2014_A2KlasseAlsContainer;

public class MainClass {

    public static void main(String[] args) {
        Results calculationA = new Results();
        calcRoots(1, 5, 6, calculationA);
        ausgabe(calculationA);
    }

    //Berechnet Ergebnisse und speichert Ergebnisse in Results-Objekt auf die die Referenz in "calculation" zeigt
    private static void calcRoots(int a, int b, int c, Results calculation) {
        int partValue = b * b - 4 * a * c;

        if (partValue > 0) {
            calculation.xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            calculation.xr_2 = (float) (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            calculation.numberResults = 2;
        }
        if (partValue < 0) {
            calculation.numberResults = 0;
        }
        if (partValue == 0) {
            calculation.xr_1  = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            calculation.numberResults = 1;
        }
    }

    private static void ausgabe(Results calculation){

        if (calculation.numberResults == 2) {
            System.out.println("Zwei Lösungen:" + calculation.xr_1 + "\t" + calculation.xr_2);
        }
        if (calculation.numberResults == 1) {
            System.out.println("Eine Lösung:" + calculation.xr_1);
        }
        if (calculation.numberResults == 0) {
            System.out.println( "Keine Lösung");
        }
    }
}

Code:
package Feb_2014_A2KlasseAlsContainer;

public class Results {

    public float xr_1;
    public float xr_2;
    public int numberResults;
}
 
Im Prinzip "ja" , aaaaaaaber!!

Erzeuge die Objekte dort, wo die Daten erzeugt werden.

Heißt: In "calcRoots" solltest du dein "Results" Objekt nicht als Parameter übergeben, sondern das "Results" Objekt erst IN dieser Methode erzeugen und dann via "return" zurückgeben. Das macht den Code deutlich sauberer und einfacher zu benutzen.
 
In Java gibt's zwar keine structs, aber ein POJO bzw. JavaBean entspricht dem zu 99%.
Also einfach ausschließlich private Properties benutzen und zu jedem Property einen public getter und public setter hinzufügen und das wars.

Wobei von einem OOP- bzw. Clean-Code-Standpunkt aus gesagt werden muss: Getter und (vor allem) Setter sind eine Seuche.

Der Code oben ist effektiv genau dasselbe wie:

Code:
public class MyBean {
    public String myProperty;
}

nur halt erheblich länger. Warum schreibt man das dann so? Meistens, weil einem mal jemand erzählt hat, dass public Properties pfui sind. Da ist auch was dran, aber man macht es mit public Gettern und Settern um keinen Deut besser.

Etwas anderes wäre es, wenn der Setter noch Validierung vornehmen würde - oder ganz fehlte, so dass der Wert von someProperty nicht nachträglich geändert werden könnte. Das wäre zumindest ansatzweise sinnvoll. Aber selbst das sieht man fast nie.

Ich würde für den Umgang mit Objekten und Properties diese Empfehlungen aussprechen:

- Ein Objekt sollte sich immer in einem gültigen Zustand befinden. Wenn dafür bestimmte Properties gesetzt sein müssen, dann werden die Werte dafür vom Konstruktor entgegengenommen und gesetzt.
- Wenn das Objekt als reiner Datencontainer dienen soll (also als Quasi-Struct), dann dürfen die Properties public final sein. Das final ist wichtig, weil es das Objekt unveränderlich macht. Dadurch werden so einige Fehlerquellen von vornherein ausgeschlossen. Stichwort: Value-Object-Pattern. Getter sind dann unnötig. Statt Settern kann es bei Bedarf (und nur dann) Methoden geben, die ein neues, abgewandeltes Objekt erzeugen und zurückgeben.
- Bei "echten" Objekten, also solchen, die neben Daten auch (Business-)Logik enthalten, sollten alle public Methoden an den Anwendungsfällen ausgerichtet sein, die für das Objekt eine Rolle spielen. Getter und Setter sind hier absolut unerwünscht.
 
benneque schrieb:
Im Prinzip "ja" , aaaaaaaber!!

Erzeuge die Objekte dort, wo die Daten erzeugt werden.

Heißt: In "calcRoots" solltest du dein "Results" Objekt nicht als Parameter übergeben, sondern das "Results" Objekt erst IN dieser Methode erzeugen und dann via "return" zurückgeben. Das macht den Code deutlich sauberer und einfacher zu benutzen.

Also so?:

Code:
package Feb_2014_A2KlasseAlsContainer;

public class MainClass {

    public static void main(String[] args) {

        Results calculationA = calcRoots(1, 5, 6);
        ausgabe(calculationA);
    }

    //Berechnet Ergebnisse und speichert Ergebnisse in Results-Objekt auf die die Referenz in "calculation" zeigt
    private static Results calcRoots(int a, int b, int c) {

        Results calculation = new Results();
        int partValue = b * b - 4 * a * c;

        if (partValue > 0) {
            calculation.xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            calculation.xr_2 = (float) (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            calculation.numberResults = 2;
        }
        if (partValue < 0) {
            calculation.numberResults = 0;
        }
        if (partValue == 0) {
            calculation.xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
            calculation.numberResults = 1;
        }
        return calculation;
    }

    //Gibt Ergebnis aus
    private static void ausgabe(Results calculation) {

        if (calculation.numberResults == 2) {
            System.out.println("Zwei Lösungen:" + calculation.xr_1 + "\t" + calculation.xr_2);
        }
        if (calculation.numberResults == 1) {
            System.out.println("Eine Lösung:" + calculation.xr_1);
        }
        if (calculation.numberResults == 0) {
            System.out.println("Keine Lösung");
        }
    }
}
 
@NullPointer: Stimmt natürlich. Außer man benutzt irgendwelche seltsamen Frameworks wie Hibernate / JPA , Spring , Jackson , Dozer und co. Also im Prinzip alles was mit Mapping zu tun hat. Manche der Tools funktionieren ausschließlich über den Zugriff über Getter und Setter und manche benutzen Annotations, die jeweils an Getter und Setter eine andere Auswirkung haben.
Aber grundsätzlich stimme ich dir natürlich zu. Schön ist es nicht. Deshalb benutz ich meist Lombok. Dann muss ich den ganzen Boilerplate Code zumindest nicht sehen und schreiben ;)

Für echte Business Objekte sollte man komplett auf die 0815-Setter verzichten. Getter sind okay, wenn sie in diesem Kontext sinnvoll sind. Wie bereits gesagt: Das Objekt sollte (eigentlich eher: MUSS) sich immer in einem konsistenten / validen Zustand befinden. Das könnte dann so aussehen:
Code:
public class MeineBusinessKlasse {
  private int einSinvollerPropertyName;
  private String nochEinSinnvollerName = "defaultValue";

  public MeineBusinessKlasse(int wert) {
    if(wert < 0) {
      throw new SinnvollerExceptionName();
    }

    this.einSinvollerPropertyName = wert;
  }

  public void macheEtwasMitDemObjekt() {
    this.nochEinSinnvollerName = "";
  }

  public void macheEtwasAnderes(String wert) {
    if(wert == null) {
      throw new NochEinSinnvollerExceptionName();
    }

    this.nochEinSinnvollerName = wert;
  }

  public ResultKlasse superKomplexeBerechnung() {
    int res = this.einSinvollerPropertyName + this.nochEinSinnvollerName.length;
    return new ResultKlasse(res);
  }

}

@yxy: Ja! Sieht schon deutlich besser aus.
Jetzt könntest du dein "Results" Objekt noch zu einem (immutable) Value-Object machen. Also quasi alle Properties im Results Object "final" machen und direkt über den Konstruktor setzen.
 
Zuletzt bearbeitet:
Code:
    private static Results calcRoots(int a, int b, int c) {

        //Results calculation = new Results();
        int partValue = b * b - 4 * a * c;

        if (partValue > 0) {
          float xr_1 = (float) (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
           float xr_2 = (float) (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
           int numberResults = 2;
           Results calculation = new Results(xr_1, xr_2, numberResults);
        }
      ....

        return calculation;
    }
Ergänzung ()

Code:
public class Results {

    public final float xr_1;
    public final float xr_2;
    public final int numberResults;

    public Results(float xr_1_, float xr_1_, int numberResults_){
    xr_1=xr_1_;
    xr_2=xr_2_;
    numberResults=numberResults_
    }
}
 
Zuletzt bearbeitet:
Status
Für weitere Antworten geschlossen.
Zurück
Oben