Methoden In Array nach double Wert suchen

geronimøø

Neues Mitglied
Moin,
ich habe eine Frage zu meiner Methode und zwar soll diese einen bestimmten Wert suchen und dann "true" oder "false" zurückgeben - je nach dem ob der Wert gefunden wurde oder nicht.
Dabei sollen wir nach Programmstart erstmal auswählen, ob wir einen Array mit int oder mit double Werten haben - deswegen steht "Object" vor dem übergebenen Parameter, die Methode soll ja schließlich für beide Datentypen verwendet werden können.
Für int Werte funktioniert die Methode problemlos, bei double Werten gibt die Methode immer "false" zurück.
Bei der Aufgabe dürfen wir nicht auf vordefinierte Klassen zurückgreifen, also kein .binarySearch oder sowas benutzen.
Vielen Dank schonmal im Vorraus!

Code:
    public boolean search(Object value){
        boolean MethodeSearch = false;
        for (int i=0; i<arr.length;i++){
            if(arr[i]==value) MethodeSearch = true; //Suchen ob irgendeine Stelle des Arrays gleich der Value ist => Dann gebe "true" zurueck
        }
        return MethodeSearch;
    }
 
Beste Antwort
Flieszkommazahlen sind, wie soll ich das ausdruecken, sie tun sich schwer sich auf einen genauen Wert festzuelegen. Die Werte sind immer nur "Annaeherungen" welche die meiste Zeit nahe genug sind, aber halt nicht immer. Daher wenn du doubles vergleichst, solltest du dir ueberlegen ob du vielleicht einen Delta-Wert nehmen willst. Also du pruefst ob die beiden doubles "nahe genug" beieinander liegen. Ich bilde mir auch ein dass Java dafuer eine Hilfsmethode haette, finde sie aber gerade nicht.

Das wird aber wahrscheinlich nicht dein Problem, dein Problem wird vermutlich Boxing sein. Du vergleichst nicht zwei primitive Werte, sondern zwei *Objekte*, und dass kann funktionieren, oder auch nicht. Ich kopiere jetzt...

Robert Zenz

Top Contributor
Flieszkommazahlen sind, wie soll ich das ausdruecken, sie tun sich schwer sich auf einen genauen Wert festzuelegen. Die Werte sind immer nur "Annaeherungen" welche die meiste Zeit nahe genug sind, aber halt nicht immer. Daher wenn du doubles vergleichst, solltest du dir ueberlegen ob du vielleicht einen Delta-Wert nehmen willst. Also du pruefst ob die beiden doubles "nahe genug" beieinander liegen. Ich bilde mir auch ein dass Java dafuer eine Hilfsmethode haette, finde sie aber gerade nicht.

Das wird aber wahrscheinlich nicht dein Problem, dein Problem wird vermutlich Boxing sein. Du vergleichst nicht zwei primitive Werte, sondern zwei *Objekte*, und dass kann funktionieren, oder auch nicht. Ich kopiere jetzt einfach mal meine alte Antwort zu dem thema:



Also es gibt zwei unterschiedliche Typen von "Werten" in Java, naemlich Primitive und Klassen. Vier der wichtigsten Unterschiede sind:

1. Primitive sind unveraenderbar und sind keine Klassen (haben keine Methoden und so weiter).
2. Primitive werden immer als Wert uebergeben, nicht als Instanz. Primitive koennen nie null sein.
3. Primitive und Klassen sind nicht austauschbar (sie wirken nur so durch den Compiler).
4. Operatoren koennen nur mit Primitiven verwendet werden (auszer halt + in Kombination mit Strings).

Primitive sind immer die kleingeschriebenen Typen, wie int oder char. Dazu gibt es dann die Klassen-Varianten wie Integer und Character.

Java:
// Primitiver Type
int wert = 5;

// Klasse
Integer wert = new Integer(5);

Da Java auf Klassen basiert, und fortgesetzt damit auf Object, ist die Konvertierung an vielen Stellen notwendig weil Methoden einfach keine primitiven Typen uebernehmen koennen ohne diese explizit zu deklarieren. In Reflection ist dies zum Beispiel der Fall. Spielt jetzt gerade aber keine Rolle.

Ich habe gesagt dass diese nicht austauschbar sind, wieso kompiliert dann folgender Code und funktioniert?

Java:
int wert = new Integer(5);
Integer wert = 5;

Die Antwort ist: Autoboxing. In dem Fall handelt es sich um "Hilfsfunktion" des Compilers welcher die Konvertierung automatisch vornimmt. Also der Code von oben wird in Wahrheit zu folgendem kompiliert:

Java:
int wert = new Integer(5).intValue();
Integer wert = Integer.valueOf(5);

Ohne das wir etwas dazu machen muessen. Die Umwandlung von Primitiv in Klasse und zurueck (Boxing) uebernimmt fuer uns der Compiler (Autoboxing).

Aber, solche Umwandlung haben immer das Potenzial eine Klasseninstanz zu erzeugen, nehmen wir zum Beispiel folgenden Code:

Java:
int result = 0;

for (int counter = 0; counter < 500; counter++) {
    result = result + counter;
}

Diese Schleife addiert ganz simpel 500 ints. Das gleiche nochmal aber mit Klassen:

Java:
Integer result = 0;

for (int counter = 0; counter < 500; counter++) {
    result = result + counter;
}

Das erzeugt zusaetzlich 501 Instanzen der Klasse Integer, was wir so nicht bemerken weil der Compiler die Umwandlung uebernimmt:

Java:
Integer result = Integer.valueOf(0);

for (int counter = 0; counter < 500; counter++) {
    result = Integer.valueOf(result.intValue() + counter);
}

Wir haben in der zweiten Variante also viel mehr Klassenabfall erzeugt als mit den primitiven Typen. Das ist etwas auf das man immer achten sollte.

In alten Java Versionen war es sogar schlimmer, valueOf verwendet einen Cache von Instanzen, also es gibt die Möglichkeit dass keine neue Instanz erzeugt wird wenn diese bereits im Cache existiert. Das ist aber ein Implementierungsdetail auf welches man sich nicht verlassen sollte. In alten Java Versionen wurde vom Compiler immer eine Instanz erzeugt:

Java:
Integer result = new Integer(0);

for (int counter = 0; counter < 500; counter++) {
    result = new Integer(result.intValue() + counter);
}

Aber das wurde korrigiert irgendwo vor 1.5, glaube ich.

Ich persoehnlich mache immer gerne die Umwandlung haendisch (man kann in den IDEs eine Warnung dafuer einschalten), einfach damit ich nie den Ueberblick verliere wo Instanzen und Objekte erzeugt und verwendet werden und wo nicht.
 
Beste Antwort

fhoffmann

Top Contributor
Double-Werte auf absolute Gleichheit zu überprüfen, klappt meistens nicht.
Stattdessen sollte man überprüfen, ob die Differenz (genauer der Absolutbetrag der Differenz) kleiner als ein kleiner Wert (Epsilon) ist.
 

KonradN

Super-Moderator
Mitarbeiter
Das Problem bei Dir ist das Boxing und die Tatsache, dass bei Double ein Literal in zwei Referenzen geboxt wird. Das was @Robert Zenz also schon erläutert hat.

Wieso Integer sich da anders verhält als Double kann ich gerade aber nicht erklären. Aber das Verhalten selbst kann man sich sehr schön im Beispiel ansehen und das möchte ich einfach einmal beisteuern.

Einmal bei Integer:

Bei Integer wurde das bei mir:
Bildschirmfoto 2022-05-20 um 15.36.39.png
Du kannst erkennen: Die 3 ist beides Male der Integer@1911 - und damit hat man dann hier die Gleichheit der Referenzen.

Bei Double sieht es aber anders aus:
Bildschirmfoto 2022-05-20 um 15.38.20.png
Hier erkennt man, dass die 3.0 im Array die Referenz Double@1943 hat und der übergebene Wert Double@1939.

Das == vergleicht die Referenz - bei dem Integer war diese gleich aber bei Double hat man zwei Instanzen und zwei unterschiedliche Referenzen.


Und natürlich der Testcode:
Java:
    @Test
    public void testDoubleCompare() {
        assertTrue(search(new Integer[]{1, 2, 3, 4}, 3));
        assertTrue(search(new Double[]{1d, 2d, 3d, 4d}, 3d));
    }

    public boolean search(Object[] arr, Object value){
        boolean MethodeSearch = false;
        for (int i=0; i<arr.length;i++){
            if(arr[i]==value) MethodeSearch = true; //Suchen ob irgendeine Stelle des Arrays gleich der Value ist => Dann gebe "true" zurueck
        }
        return MethodeSearch;
    }
 

DefconDev

Bekanntes Mitglied
Also es gibt zwei unterschiedliche Typen von "Werten" in Java, naemlich Primitive und Klassen. Vier der wichtigsten Unterschiede sind:

1. Primitive sind unveraenderbar und sind keine Klassen (haben keine Methoden und so weiter).
2. Primitive werden immer als Wert uebergeben, nicht als Instanz. Primitive koennen nie null sein.
3. Primitive und Klassen sind nicht austauschbar (sie wirken nur so durch den Compiler).
4. Operatoren koennen nur mit Primitiven verwendet werden (auszer halt + in Kombination mit Strings).

Primitive sind immer die kleingeschriebenen Typen, wie int oder char. Dazu gibt es dann die Klassen-Varianten wie Integer und Character.

Ich möchte das gerne etwas verbessern bzw. ergänzen.

Die Unterscheidung oder Abgrenzung in Java ist in primitive/elementare Datentypen und in Objekte, nicht in Klassen. Es gibt 8 elementare Datentypen, jeder hat ein Wrapper Klasse als äquivalent.

In Java ist ALLES Copy by Value. In Java werden nie Instanzen übergeben, auch nicht bei Objekten.

Operatoren können nicht auf Objekte angewendet werden, das sogenannte Operator Overloading. Es gibt aber Umwege ähnliches Verhalten zu implementieren.

Zum Schluss noch was zum Caching von Integer Werten in der Range von -128 bis 127 seit Java 5.


Wusste ich auch lange Zeit nicht, aber sowas nehme ich dann ganz gerne in mein Java Quiz auf für neue Entwickler um die zu ärgern :D

Bisher wusste es nur ein Entwickler...
 

Robert Zenz

Top Contributor
Wusste ich auch lange Zeit nicht, aber sowas nehme ich dann ganz gerne in mein Java Quiz auf für neue Entwickler um die zu ärgern :D

Bisher wusste es nur ein Entwickler...
Versteh' mich nicht falsch, ist schon richtig alles, aber wenn da jetzt jemand auf solchem Trivia herumreitet weisz ich auch was los ist.

In Java ist ALLES Copy by Value. In Java werden nie Instanzen übergeben, auch nicht bei Objekten.
Ob die Zeiger auf die Instanz jetzt per Referenz oder per Kopie uebergeben werden, spielt fuer einen Anfanger der noch nicht verstanden hat was eine Klasse ist keine Rolle. Da ist es wichtiger das Verhalten zu verstehen. Und das Verhalten ist effektiv das primitive als Kopie, und Klasseninstanzen als Referenzen uebergeben werden. Oder halt das primitive konstant sind...ist zu frueh fuer die richtige Formulierung.

Operatoren können nicht auf Objekte angewendet werden, das sogenannte Operator Overloading. Es gibt aber Umwege ähnliches Verhalten zu implementieren.
Ja, das ist richtig, steht ja auch immer ein StringBuilder dahinter.

Zum Schluss noch was zum Caching von Integer Werten in der Range von -128 bis 127 seit Java 5.
Tatsaechlich ist in JLS 5.1.7 festgehalten dass es den Cache in der Groesze geben muss. Wusste ich bis jetzt auch nicht, dachte immer das waere ein Implementierungsdetail. Aber die Obergrenze koennte hoeher sein, je nach Konfiguration, und das betrifft nicht Long.
 

Robert Zenz

Top Contributor
Uff, immer noch schlechte Beispiele auf der Seite..."Integer Cache works only on autoboxing.", zeigt das Beispiel mit Autoboxing und erklaert dann weiter unten das Autoboxing effektiv "new Integer(x)" ist, "Integer cache gives you the facility to cache other objects also for Example like Byte, Short, Long, etc." und so weiter...
 

KonradN

Super-Moderator
Mitarbeiter
Operatoren können nicht auf Objekte angewendet werden
Wenn man genau sein will, dann ist dies falsch.

Operatoren können so angewendet werden, wie es die JLS vorgibt.

So ist bei + einiges mehr erlaubt. Und Wrapperklassen wären ja auch Referenztypen.

Und wenn man beim Wording genau sein will, dann geht es nicht um Objekte sondern um Referenzen (oder Referenz-Variablen)
 

DefconDev

Bekanntes Mitglied
Wenn man genau sein will, dann ist dies falsch.

Operatoren können so angewendet werden, wie es die JLS vorgibt.

So ist bei + einiges mehr erlaubt. Und Wrapperklassen wären ja auch Referenztypen.

Und wenn man beim Wording genau sein will, dann geht es nicht um Objekte sondern um Referenzen (oder Referenz-Variablen)
OK, das wusste nicht danke dafür.

Aber beim Wording bin ich nicht ganz deiner Meinung. In der Fachliteratur ist immer von der Abgrenzung von Objekten und primitiven Datentypen die Rede. Sicherlich sind Objekte in der Regel unweigerlich verbunden mit Referenzen aber das Objekt an sich ist doch "das", welches irgendwo im Speicher liegt. Und die Referenz verweist auf diesen Speicherbereich.
 

KonradN

Super-Moderator
Mitarbeiter
Aber beim Wording bin ich nicht ganz deiner Meinung. In der Fachliteratur ist immer von der Abgrenzung von Objekten und primitiven Datentypen die Rede. Sicherlich sind Objekte in der Regel unweigerlich verbunden mit Referenzen aber das Objekt an sich ist doch "das", welches irgendwo im Speicher liegt. Und die Referenz verweist auf diesen Speicherbereich.
Das Objekt entspricht der realen Instanz. Die hast Du aber nicht. Alles, womit Du (Zur Laufzeit) arbeiten kannst, ist die Referenz. Aber selbst die hast Du im Code nicht. Im Code hast Du nur eine Variable oder einen Ausdruck, der eben zu einer Art Platzhalter für eine Referenz aufgelöst werden kann (Bei der halt bei der Ausführung eine Referenz zurück kommt).

Aber da kommt auch nur eine Referenz - nie ein Objekt / eine Instanz. Und das kann dann z.B. auch die Nullreferenz sein. Das kann auch eine Instanz sein, die von dem Typ abgeleitet ist oder die das Interface implementiert.

Bei der Sprache selbst geht es ja um das Programmieren, die Syntax - also nicht um die Laufzeit. Daher kann also auch gar nicht um Instanzen gehen, denn die existieren schlicht zur Entwicklungszeit nicht :)
 

Neue Themen


Oben