Vererbung null aus Elternklasse "dominant"?

Tobse

Top Contributor
Hi,
ich habe folgende Situation:
Java:
public abstract class Foo {
    public int[] FIELD1=null;
    // Das =null muss da stehen
}
Java:
public class Extra extends Foo {
    public int[] FIELD1=new int[] { ... };
}
Java:
public class Worker {
    private Foo container;
    public Worker(Foo con, ...) {
         this.container=con;
         ...
    }
    public void doSomething() {
         ...
         int[] id=(aus Stream gelesen);
         if (compare(id, this.container.FIELD1)) {
             ...
         }
    }
}
Java:
public class Start {
    public static void main(String[] args) {
        Worker w=new Worker(new Extra(), ...);
        ...
        w.doSomething();
        ...
    }
}
Compiliert korrekt.
Bie der ausführung:
Code:
!'#%§~ bratzel => Worker @Line10: NullPointerException

Aber warum? Die Instanz von Extra überschreibt ja das Null der Elternklasse. Wenn ich im Konstruktor von Extra das array ausgebe kommt auch was.
Aber die referenz von FIELD1 auf Extra scheint im Worker nicht zu fruchten.

Bitte zerr mich da mal jmd. vom Schlauch runter 😉.
 
Du meinst wohl eher:

Java:
public class Extra extends Foo {
    /* public int[] */ FIELD1=new int[] { ... };
}

oder war die erneute Deklarierung einer bereits in der Vaterklasse deklarierten Variable für dieses Szenario absichtlich herbeigeführt?
 
this.container ist vom Typ Foo, also sagst du ihm explizit dass er die Variable aus Foo nutzen soll.

Warum hast du die Variable eigentlich doppelt deklariert? Einmal in der Klasse Foo reicht. Die Klasse Extra kann die Variable dann ja noch umsetzen.
 
Deine Extra Klasse hat einfach ein zusätzliches Feld, jetzt gibt es Foo.FIELD1 und Extra.FIELD1. Anders als Methoden werden Felder aber nicht überschrieben, wenn du auf das Foo.FIELD1 zugreiffst, greiffst du immer auf Foo.FIELD1 zu.

Entweder packst du den Zugriff auf dieses FIELD1 in eine (abstrakte) Methode die du dann überschreiben kannst (oder musst), oder deine Extra Klasse ruft "FIELD1 = new ..." im Konstruktor auf.

Ganz egal welche Lösung du wählst, nicht konstante Felder sollten in jedem Fall "private" und nicht "public" sein.
 
Das mit der Doppelten deklarierung stand nch so im Quellcode wiels vorher ein Interface war, aber da war das gleiche Problem.
Ganz egal welche Lösung du wählst, nicht konstante Felder sollten in jedem Fall "private" und nicht "public" sein.
Ich kann die ja nicht konstant machen, weil ich sie sonst in Extra nichtmehr überschreiben kann. Und private will ich die nicht machen, weil ich dann 20 getter machen muss, die mir nichts erleichtern.

Ohne die doppelte deklarierung heissts
Code:
C:\...Datei...\x.java:6: <identifier> expected
    HEADER_OBJECT=new int[] {
                 ^
Das machts nich besser :|
 
Java:
public class Extra extends Foo{
  FIELD1 = new ... // Zuweisungen ausserhalb einer Methode funktionieren nicht (Ausnahme: es wird ein neues Feld angelegt).

  public Extra(){
    FIELD1 = new ... // im Konstruktor darfst du
  }
}

Falls der Hinweis nicht hilft: poste die ganzen Klassen und nicht nur Ausschnitte.
 
Hier deklarieren:
Java:
public class Foo {
	public String s = null;
}

Hier neu setzen:
Java:
public class Extra extends Foo {
	public Extra() {
		s = "Extra"; // oder in nem initializer block
	}
}

Und so nutzen:
Java:
public class Main {
	public static void main(final String[] args) {
		Foo f = new Extra();
		System.out.println(f.s);
	}
}
Setter solltest du dir aber auf jedenfall auch noch zulegen.
 
OK, ich pack das alles mal in den konstruktor.
Setter solltest du dir aber auf jedenfall auch noch zulegen.
Die brauchts in diesem Fall hier nicht, weil das eigentlich auch Enums sein könnten, klappt aber aus dem besagtne grund auch nicht ...

Jap, das mit dem Konstruktor hat geklappt. In Java wünsche ich mir manchmal einfach die schönen anonymen objekte aus JS, die sind soooo cool xD. Danke für deine Hilfe.
 
Und private will ich die nicht machen, weil ich dann 20 getter machen muss, die mir nichts erleichtern.

Datenkapselung Note: 6!

In der Tat, Getter erleichtern gar nichts. Sie sind nur ein nötiger Seiteneffekt. Bei der Kapselung geht's um die Setter. Und dass du die nicht brauchst, das kann dir vielleicht jetzt so vorkommen. Aber wehe, du willst im Nachhinein noch irgendeine Art Kontrollabfrage bei der Zuweisung einer Variablen integrieren.

Die brauchts in diesem Fall hier nicht, weil das eigentlich auch Enums sein könnten
hat damit übrigens auch gar nichts zu tun.
 
In der Tat, Getter erleichtern gar nichts. Sie sind nur ein nötiger Seiteneffekt. Bei der Kapselung geht's um die Setter. Und dass du die nicht brauchst, das kann dir vielleicht jetzt so vorkommen. Aber wehe, du willst im Nachhinein noch irgendeine Art Kontrollabfrage bei der Zuweisung einer Variablen integrieren.
Der Sinn von Getter und Setter ist mir durchaus bekannt. Allerdings sollen diese Werte nicht geändert werden. Die sollten von mir aus [c]public static final[/c] sein, das ist hier aber nicht möglich, wegen der vererbung.
Alles was diese Klassen sollen, ist die möglichkeit geben, den Worker mit anderen Werten rechnen zu lassen. Und die muss ich 1 mal definieren, und damit wars das. Es handelt sich bei diesen arrays um IDs in WMA-Dateien. Die ändern sich nicht so, dass ich die im programmablauf ändern müsste.
 
Achso, ich verstehe. Ich denke in dem Fall bräuchten wir (oder sagen wir mal ich) genauere Informationen über den Sinn und die Verwendung dieser Datenstrukturen im Programm, um dir ein passenderes Design vorzuschlagen. Konstanten (statische Dinge im Allgemeinen) lassen sich nun mal nicht vererben, wie du gemerkt hast.
 
Es geht hier im Generellen um das ASF-Format. In diesen Dateien sind Audio/Video Informationen in form von "objekten" gespeichert. Das sieht dann z.B so aus:
Code:
Field         | Size (Byte)
--------------+--------------
Object ID     | 16
--------------+--------------
Object Size   | 8
--------------+--------------
Field1 Length | 4
--------------+--------------
Field1        | s.o.
--------------+--------------
Field2 Length | 4
--------------+--------------
Field2        | s.o.
usw.
Um jetzt entscheiden zu können um was für ein Objekt, also um welche informationen, es sich handelt, gibt es die GUID. Das sind 16 byte, da gibts kein bestimmtes muster.
In ASF Dateien ist pro objekt genau 1 ID definiert. Das WMA-Format "erbt" von ASF, nur das dort anderee IDs für die gleichen Informationen gelten. Um jetzt mit einer Klasse mehrere Datei-Formate lesen zu können wollte ich diese IDs extrahieren und bin dabei an der Java vererbung gescheitert. Diese weise schien mir die einzig sinnvolle zu sein... es funktioniert auf alle fälle.
 
In Java wünsche ich mir manchmal einfach die schönen anonymen objekte aus JS,
Gibts doch in Java auch? Oder meinst du was anderes als:
Java:
		Foo f = new Foo() {
			{
				s = "Anonymer Foo";
			}
		};
		System.out.println(f.s);
???:L
 
Diese Schreibweise war mir nicht bekannt. In JS ist das ja
Code:
var obj={
    foo: bar,
    x: "y"
};
Aber in Java hab ich auf diese Weise nichts hinbekommen.
EDIT:
Anonyme Objekte in Java kannte ich auch davor, aber dass da nochmal ein {} reinmuss, da bin ich nich draufgekommen.
 
Dieses {} im Klassenrumpf schimpft sich (nicht-statischer) Initialisierungs-Block. Das hat erstmal nichts mit anonymen Klassen zu tun, das lässt sich an jeder beliebigen (top-level) Stelle innerhalb jedes Klassen-Rumpfes schreiben. Solche Init-Blöcke werden im Zuge der Instanz-Variablen-Initialisierung ausgeführt. (d.h. zwischen (implizitem) super-Aufruf im Konstruktor und den restlichen Anweisungen im Konstruktor)
 
Der
Code:
{ }
-Block ist für die Initialisierung der Instanz da. Nennt sich auch double brace initialization wenn ich da jetzt nichts verwechsele.
 

Zurück
Oben