Freie Stelle eines Arrays

Ap0

Mitglied
Hallo zusammen,

ich habe leider ein Problem mit einer Java-Aufgabe, das Thema ist (einfache) Objektorientierung und speziell Arrays.
Und zwar soll ich zunächst eine Klasse DynamicArray erstellen, die als einziges Attribut einen Integer-Array besitzt. Dieser Array soll dann mit Hilfe von einem (von drei verschiedenen) Konstruktoren mit einer bestimmten Länge initialisiert werden; so weit so gut.
Jetzt soll ich eine Objektmethode implementieren, die an der ersten freien Stelle des Arrays einen übergebenen Wert einfügt.
Hier beginnt mein Problem bereits bei der Aufgabenstellung? Was genau ist eine "freie Stelle"? Anfangs bin ich davon ausgegangen, dass damit ein Feld gemeint ist, in dem eine "0" steht. Da die Null ja aber auch sehr wohl ein Wert sein kann, ist das wohl falsch; außerdem habe ich folgenden Hinweis bekommen: "Eine 0 ist ein Wert, wenn der Index des Feldes kleiner der Größe ist, ansonsten handelt es sich um ein freies Feld". Leider kann ich mit dieser Definition absolut nichts anfangen.

Ich hoffe dass ihr mir helfen könnt; bei Bedarf kann ich natürlich noch meinen bisherigen Code einfügen.
 
Naja also die erste "freie" Stelle in einem Array ist die Stellen, welche durch keinen Wert belegt ist 😉

Umsetzen könntest du diese Methode z.B. so:
Java:
public void setElement(int number){
    array[counter] = number;
    counter++;
}
 
Das Schlüsselwort ist null. Das funktioniert aber nur, wenn du Integer schreibst und nicht int.

Java:
public class Hauptprogramm {

    public static void main(String[] args) {

        Integer[] arrInt = new Integer[5];

        if (arrInt[3] == null) {
            System.out.println("Treffer");
        }

        System.out.println(arrInt[3]);
    }
}
Ausgabe:
Code:
Treffer
null
 
@krgewb: Auch dir vielen Dank, allerdings hätte ich noch eine Frage zu deinem Code: wenn man statt int Integer verwendet, handelt es sich wohl um Objekte, die in den Feldern des Arrays stehen? Andernfalls würde der Vergleich mit "null" ja nicht funktionieren, wenn ich mich nicht täusche?
 
Kein Problem 😉 Was @krgewb dir etwas näher bringen wollte ist, dass solltest du beispielsweise mit Objekten arbeiten, kannst du über das Array iterieren und an der Stelle wo "null" auftritt ein Element einfügen 😉
 
@krgewb: Auch dir vielen Dank, allerdings hätte ich noch eine Frage zu deinem Code: wenn man statt int Integer verwendet, handelt es sich wohl um Objekte, die in den Feldern des Arrays stehen? Andernfalls würde der Vergleich mit "null" ja nicht funktionieren, wenn ich mich nicht täusche?
Also in den Speicherzellen selbst stehen bei Objekten keine wirklichen Werte sondern lediglich Referenzen zu den Objekten 😉 Deshalb nennt man sie auch Referenzdatentypen 🙂
 
Was genau ist eine "freie Stelle"?

Es macht einen Unterschied, ob man ein Array von primitiven Typen oder ein Array von Objekten hat.

Probier das mal aus:
Java:
public class Main {

    public static void main(String[] args) {

        int[] a1 = new int[2];
        Integer[] a2 = new Integer[2];

        System.out.println(Arrays.toString(a1));
        System.out.println(Arrays.toString(a2));
    }
}

// Ausgabe

[0, 0]
[null, null]

Beim int-Array wird jede Stelle bei der Erzeugung mit dem Wert 0 initialisiert und kann auch direkt beschrieben werden a1[0] = 42;.

Beim Integer-Array (Integer ist eine sog. Wrapper-Klasse für int, es handelt sich also um Objekte) wird jede Stelle mit "null" initialisiert. Das kann man sich so vorstellen, als wäre das Array ein Regal, in dem man "Integer-Objekte" reinstellen kann. Mit der Erzeugung wird ein leeres Regal erstellt. Die Objekte müssen noch reingestellt werden, z.B. a2[0] = new Integer(42);. Und wie @Kirby_Sike schon geschrieben hat, enthält das Array nur die Referenzen auf die darin gespeicherten Objekte.
 
@Kirby_Sike Integer verhält sich trotzdem anders als gewöhnliche Klassenobjekte (bezüglich Call By Value bzw. Call By Reference). Ich habe es hier erklärt: https://www.java-forum.org/thema/callbyvalue.183910/#post-1174042

Bei Integer:
Java:
public class Hauptprogramm {

    public static void main(String[] args) {

        Integer value1 = 123;
        Integer value2 = 456;

        value1 = value2;

        value2 = 789;

        System.out.println(value1);
    }

}
Ausgabe:
456
 
@Kirby_Sike Integer verhält sich trotzdem anders als gewöhnliche Klassenobjekte (bezüglich Call By Value bzw. Call By Reference). Ich habe es hier erklärt: https://www.java-forum.org/thema/callbyvalue.183910/#post-1174042

Bei Integer:
Java:
public class Hauptprogramm {

    public static void main(String[] args) {

        Integer value1 = 123;
        Integer value2 = 456;

        value1 = value2;

        value2 = 789;

        System.out.println(value1);
    }

}
Ausgabe:
456

Eigentlich verhält es sich wie jedes andere Objekt, wenn man es mal so ausschreibt, wie es letztlich vom Compiler behandelt wird:
Java:
public class Hauptprogramm {

    public static void main(String[] args) {

        Integer value1 = new Integer(123); // tatsächlich ist es wohl Integer.valueOf(123), es wird jedenfalls eine Instanz von Integer erzeugt.
        Integer value2 = new Integer(456); // dito

        value1 = value2; // Referenz von value2 wird value1 zugewiesen

        value2 = new Integer(789); // value2 wird eine Referenz auf eine neue Instanz zugwiesen.

        System.out.println(value1);
    }

}
Oder habe ich dich falsch verstanden und du meinst etwas anderes.

In deinem verlinkten Beispiel weist du der Variablen auch keine neue Instanz zu, sondern änderst über eine Settermethode den Zustand der ursprünglichen Instanz in der Art von value2.setValue(789);. Allerdings stellt "Integer" diese Möglichkeit nicht zur Verfügung.
 
Zuletzt bearbeitet:
Was hier vielleicht für ein bisschen Verwirrung sorgt, ist der Unterschied zwischen mutable (veränderbaren) und immutable (unveränderbaren) Objekten.
java.lang.Integer (sowie alle anderen Wrappertypen und auch java.lang.String) sind unveränderbar und somit von Außen auch nicht von "Value"-Typen unterscheidbar (außer vielleicht durch ihre Objektidentität, wenn man darauf synchronisiert). Zwei Variablen können zwar auf dieselbe java.lang.Integer (oder java.lang.String) Instanz "zeigen"; dadurch, dass man aber diese Instanzen in ihrem Wert intern nicht verändern kann, macht es für diese Betrachtung keinen Unterschied, ob man einen java.lang.Integer oder ein int nutzt.
 
Wie kann ich das per Konsolenausgabe nachvollziehen?
Was meinst du damit?

Integer ist eine Klasse. "value1" und "value2" sind beides Instanzen der Klasse Integer und enthalten somit Referenzen. Die Zuweisung value1 = value2; funktioniert, wie bei jeder anderen Instanz einer Klasse. Und mit der Ausgabe System.out.println(value1); zeigst du ja schon, worauf die Referenz zeigt.

Wichtig ist die Ergänzung von @httpdigest, dass Instanzen von Integer immutabel sind. Es gibt kein value2.setValue(789). Der Compiler macht aus der Zuweisung eines int an eine Integer-Variable value2 = 789; ein value2 = Integer.valueOf(789); und erzeugt eine neue Instanz.
 
Integer ist eine Klasse. "value1" und "value2" sind beides Instanzen der Klasse Integer und enthalten somit Referenzen. Die Zuweisung value1 = value2; funktioniert, wie bei jeder anderen Instanz einer Klasse. Und mit der Ausgabe System.out.println(value1); zeigst du ja schon, worauf die Referenz zeigt.
Falls du gemeint hast, dass diese Zuweisung auch eine neue Instanz erzeugt; keine Ahnung. Müsste man mal in der Java Language Specification nachschauen oder jemanden fragen, der sich darin wie zuhause fühlt.
 
Wie kann ich das per Konsolenausgabe nachvollziehen?
Java:
public class Main {

    public static void main(String[] args) {

        Integer value1 = 123;
        Integer value2 = 456;

        System.out.println(System.identityHashCode(value1));
        System.out.println(System.identityHashCode(value2));

        value1 = value2;

        System.out.println(System.identityHashCode(value1));
        System.out.println(System.identityHashCode(value2));
     
        value2 = 789;

        System.out.println(System.identityHashCode(value1));
        System.out.println(System.identityHashCode(value2));
    }
}
618365781
140435067
140435067
140435067
140435067
1450495309

Ein Versuch es nachzuvollziehen. Ich bin aber nicht sicher, ob der Hashcode nicht einfach aus dem Wert gebildet wird.
 
Zuletzt bearbeitet:
Eine zweiter Versuch. Ich gebe zu, das hier viel copy & paste im Spiel ist😉
Java:
import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class Main {

    private static Unsafe unsafe = getUnsafe();

    public static void main(String[] args) {

        Integer value1 = 123;
        Integer value2 = 456;

        printAddresses("value1", value1);
        printAddresses("value2", value2);

        value1 = value2;

        printAddresses("value1", value1);
        printAddresses("value2", value2);

        value2 = 789;

        printAddresses("value1", value1);
        printAddresses("value2", value2);
    }

    public static void printAddresses(String label, Object... objects) {
        System.out.print(label + ": 0x");
        long last = 0;
        int offset = unsafe.arrayBaseOffset(objects.getClass());
        int scale = unsafe.arrayIndexScale(objects.getClass());
        switch (scale) {
            case 4:
                long factor = 8; // 64 Bit
                final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
                System.out.print(Long.toHexString(i1));
                last = i1;
                for (int i = 1; i < objects.length; i++) {
                    final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
                    if (i2 > last)
                        System.out.print(", +" + Long.toHexString(i2 - last));
                    else
                        System.out.print(", -" + Long.toHexString( last - i2));
                    last = i2;
                }
                break;
            case 8:
                throw new AssertionError("Not supported");
        }
        System.out.println();
    }

    private static Unsafe getUnsafe() {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            return (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}
value1: 0x7bfc46818
value2: 0x62860d4a0
value1: 0x62860d4a0
value2: 0x62860d4a0
value1: 0x62860d4a0
value2: 0x628658f38
 

Zurück
Oben