Cast

wakoz

Erfahrenes Mitglied
Moin

Ich möchte die Klasse File erweitern, was hat das mit Casten zu tuen? ;)

Ganz einfach, ich verwende Java Bordmittel und die liefern mir ein File Objekt.
Daher wollte ich einfach ein Cast durchführen. Aber zur laufzeit bekomme ich eine ClassCastExeption.

Und ich verstehe nicht warum, da das Object in das ich Caste von File erbt. ich Überschreibe nichts und behalte soweit alles! Meine File Klasse erbt von File und erweitert nur um einige Parameter die eine Standard Belegung haben und die dazu gehörige Methoden.

Beim Casten kann ich doch in alle möglichen Richtungen Casten, muss aber beachten das werte verloren gehen oder nicht besetzt sind nach dem Cast
 
Hi

ich bin mir zwar nicht ganz sicher, was du willst, aber Nein.
Du kannst nicht wahllos herumcasten.

Wenn du ein Objekt hast, das tatsächlich ein File ist, kann das zu Variablen vom Typ File und allen Superklassen zugewiesen werden.

Gruß
 
Hallo wakoz,

wenn du ein File Objekt aus den Bordmitteln beziehst, hast du ja eine Methode aufgerufen, die dir auf jeden Fall ein File Objekt zurück gibt! Du kannst natürlich eine weitere Subklasse von File erstellen.
In der Hierarchie steht deine Klasse ja weiter unten. Oberklasse von File ist Object.
Beim Casten kann ich doch in alle möglichen Richtungen Casten, muss aber beachten das werte verloren gehen oder nicht besetzt sind nach dem Cast
Hochcasten darfst du bedenkenlos, mit den von dir bereits erwähnten Eigenschaften, in diesem Fall nur nach Object.
Runtercasten darfst du allerdings nur, wenn dein zu castendes Objekt tatsächlich von dem jeweiligen Subtyp ist. Java kann die fehlende Information nirgends herzaubern, hast du ja auch schon richtig erkannt. Leere möglicherweise inkonsistente Felder in einer Klasse darf es in Java bestenfalls nie geben, daher verbietet Java es an der Stelle einfach! In anderen Sprachen ist der downcast zu fremden Typen möglicherweise erlaubt(c++ erlaubt sowas glaub ich). Am sichersten ist es, sich vor einem Cast mit dem instanceof Operator den Cast abzusichern und erst anschließend durchzuführen. Es gibt natürlich auch Fälle in denen man weiß das der Cast immer gelingen wird, da braucht man nicht explizit zu prüfen. Man sollte es aber vermerken, dass man sich darüber Gedanken gemacht hat! ;)

Schau mal hier:
Java:
class MyFile extends File {
	public MyFile(String str) {
		super(str);
	}
}

// klasse auf die du keinen direkten einfluss hast
// irgendeine system klasse oder fremd bibliotheksklasse
// Ich hoffe ich habe die von dir genannten "Bordmittel" richtig interpretiert.
class Bordmittel {
	public static File irgendeinSub() {
		return new File("test");
	}

	public static File irgendeinSub2() {
		return new MyFile("test");
	}
}

public class CastTest {
	public static void main(String[] args) {
		File sub = Bordmittel.irgendeinSub(); // #1
		Object base = (Object) sub; // #2 upcast
		MyFile subA;
		if (sub instanceof MyFile) // false
			/* not reached */
			subA = (MyFile) sub; // #3 downcast -> ClastCastException

		File sub2 = Bordmittel.irgendeinSub2(); // #4
		Object base2 = (Object) sub2; // #5 upcast
		MyFile subA2;
		if (sub2 instanceof MyFile) // true
			subA2 = (MyFile) sub2; // #6 downcast

	}
}

gruß
isaias
 
@isaias_b

also muss ich erst das file Objekt zu Object umwandeln um es in die form zu bringen in der ich es haben möchte...mmh

gehen denn nicht die Inhalte von File verloren? die benötige ich auch! oder...

wenn es so ist wie ich es von meinen JDom arbeiten, dann sollte alles erhalten bleiben und ich verstehe warum ich die element liste von JDom immer nur Objekte lieferte :)

Ich gleube ich bleibe meiner Mehr dim Array Lösung
 
also muss ich erst das file Objekt zu Object umwandeln um es in die form zu bringen in der ich es haben möchte...mmh
Nein, auch zuerst in Object casten wird dir hier nicht helfen.
Wenn beim Erstellen mit new "File" angegeben worden ist, bleibt das Objekt ein File; egal ob es jetzt in einer File- oder in einer Objectvariable gespeichert ist.
Speichern kannst du es in Variablen vom Typ File und allen Typen, von denen File was erbt.
Also zB Object.

Wenn du jetzt eine Klasse MyFile hast, die von File erbt:
Mit "new MyFile()" legst du jetzt eben ein MyFile-Objekt an.
Dieses kann in MyFile-, File- und Object-Variablen gespeichert werden.

In diese Richtung gehts also immer.

Umgekehrt aber nicht:
Wenn du ein Object x hast und weißt, das der Inhalt aber mit "new MyFile()" angelegt wurde, kannst du x in File oder MyFile casten.
Wenn der Inhalt von x aber mit "new Object()" angelegt wurde, kannst du es nicht in File oder MyFile casten.

Ausschlaggebend ist immer der Typ, der beim new angegeben wird.
Casten kannst du in diesen Typen und alle, von denen dieser Typ was erbt.
Aber nicht in andere Klassen, die umgekehrt vom Typ selber erben.

gehen denn nicht die Inhalte von File verloren? die benötige ich auch! oder...

Nein, da gehts nichts verloren. Wie gesagt, ein
Java:
Object x=new File();
bleibt immer ein File, auch wenn es in einer Object-Variable ist.

Gruß
 
Hallo,

@isaias_b
also muss ich erst das file Objekt zu Object umwandeln um es in die form zu bringen in der ich es haben möchte...mmh

Würde ich so nicht sagen. Es kommt ja darauf an was du letzendlich brauchst.
Also ich mutmaße mal.
Du möchtest von einem File Objekt das es sich verhält wie ein MyFile Objekt?
Wenn ja, wär der Cast meines Wissens für dich keine Möglichkeit. Stattdessen wäre ein Objektadapter das Richtige.

@isaias_b
gehen denn nicht die Inhalte von File verloren? die benötige ich auch! oder...

Nein, die Inhalte bleiben. Ein File Object bleibt immer ein File Object der Cast erlaubt die Zuweisung an einer Variablen anderen Typs. Bei einem Upcast nach Object hast du dann lediglich Zugriff auf die Methoden von Object. Es steht dir aber jederzeit frei, dieses in der neuen Variablen abgelegte Objekt zurück in eine File Variable zu schreiben mit einem Downcast. Anschließend kannst du es wieder als das File Objekt verwenden das es letzendlich ja ist. Die Casts von Objekten/Referenzen/Instanzen unterscheidet sich von dem der Primitiven(int, char, double,...) bei diesen ist es durchaus der Fall das Information verloren geht! Die bei Hoch und Runtercasten dauerhaft verloren bliebe.

Schau mal hier:
Java:
class MyClass extends Object {
	int a = 123;
}

public class CastTest {
	public static void main(String[] args) {
		double d = 3.14159265358979323846;
		int i = (int) d;
		double d2 = (double) i;
		
		System.out.println(d2 == d); // -> false
		
		MyClass mc1 = new MyClass();
		Object obj = (Object) mc1;
		MyClass mc2 = (MyClass) obj;
		
		System.out.println(mc1.a == mc2.a); // -> true
	}
}

@isaias_b
wenn es so ist wie ich es von meinen JDom arbeiten, dann sollte alles erhalten bleiben und ich verstehe warum ich die element liste von JDom immer nur Objekte lieferte :)

Ich gleube ich bleibe meiner Mehr dim Array Lösung

:confused: Damit konnte ich leider nicht sehr viel anfangen :( möglicherweise könntest du dich nochmal etwas klarer fassen.

Gruß isaias
 
....

:confused: Damit konnte ich leider nicht sehr viel anfangen :( möglicherweise könntest du dich nochmal etwas klarer fassen.

Gruß isaias

klarer fassen... das hast du schon getan :D

und zwar mit
Nein, die Inhalte bleiben. Ein File Object bleibt immer ein File Object der Cast erlaubt die Zuweisung an einer Variablen anderen Typs. Bei einem Upcast nach Object hast du dann lediglich Zugriff auf die Methoden von Object. Es steht dir aber jederzeit frei, dieses in der neuen Variablen abgelegte Objekt zurück in eine File Variable zu schreiben mit einem Downcast. Anschließend kannst du es wieder als das File Objekt verwenden das es letzendlich ja ist. Die Casts von Objekten/Referenzen/Instanzen unterscheidet sich von dem der Primitiven(int, char, double,...) bei diesen ist es durchaus der Fall das Information verloren geht! Die bei Hoch und Runtercasten dauerhaft verloren bliebe.

Bei einer anderen Anwendung von mir habe ich mit JDom XML Dokumente gelesen.

Und eine JDom Methode ( ich glaube es war getElements() ) lieferte mir immer eine Liste von Objects zurück, was nervig war weil man alle Objekte zu Element Casten musste.

ABER
Auf den Selben Baum Ebenen konnten auch andere Typen liegen, diese intern als Objekte zu behandeln war wohl für die JDom Entwickler einfacher. das Nachträgliche Casten in die Urform also Element zu Element String zu String usw. macht für mich nun mehr sinn ;)


Was ich Vorhabe....
Ich will eine JTable füllen und im Code wäre es einfacher mit nur einem Objekt und dessen Inhalten zu Arbeit, als einen Liste von Informationen jedes mal rum zu reichen.

Mein Tablemodel sollte nur ein Objekt halten und je nach spalte andere Informationen raus suchen, vor allem in Verbindung mit dem Renderer wäre es ein nettes Feature.

Im Grunde reicht mir eine File Objekt, ich wollte aber via Renderer die Tabellen Zellen Farblich verändern. Dazu brauchte ich eine Information die im Direkten Zusammenhang zum File Objekt steht und auch an Anderen stellen wichtig wird. Daher wollte ich das File Objekt erweitern, aber weil ich im Laufe der Programmablaufes mehrfach neue Objekte von der VM erzeugen lasse (und anders geht es nicht!) die vom Typ File sind reicht es nicht mit new MyFile() zu erzeugen. Daher dachte ich an einen Cast da die Typen nur in den zusätzlichen Informationen unterscheiden und direkt nach dem Cast sind die Erweiterungen unwichtig, erst im späteren Programm verlauf würden die Felder Angepasst bevor der Inhalt wichtig wird.

jetzt halte ich im Model nicht nur ein Array welches die File Objekte hält, sondern auch die Informationen die ich in mein MyFile haben wollte. Was erschwert die Zellen zu Färben :(
 
Hi wakoz,

gut das ich schon ein paar Unklaarheiten beseitigen konnte ^^

Im Grunde reicht mir eine File Objekt, ich wollte aber via Renderer die Tabellen Zellen Farblich verändern. Dazu brauchte ich eine Information die im Direkten Zusammenhang zum File Objekt steht und auch an Anderen stellen wichtig wird. Daher wollte ich das File Objekt erweitern, aber weil ich im Laufe der Programmablaufes mehrfach neue Objekte von der VM erzeugen lasse (und anders geht es nicht!) die vom Typ File sind reicht es nicht mit new MyFile() zu erzeugen. Daher dachte ich an einen Cast da die Typen nur in den zusätzlichen Informationen unterscheiden und direkt nach dem Cast sind die Erweiterungen unwichtig, erst im späteren Programm verlauf würden die Felder Angepasst bevor der Inhalt wichtig wird.

jetzt halte ich im Model nicht nur ein Array welches die File Objekte hält, sondern auch die Informationen die ich in mein MyFile haben wollte. Was erschwert die Zellen zu Färben :(

Du möchtest also deine File Ojbekte im TableModel halten die ausgegeben werden sollen.
Darüberhinaus möchtest du all diese Files mit der selben Art von Zusatzinformation versehen?
bspw. backgroundColor oder sonste was? Ich würde dann empfehlen eine Klasse zu schreiben die alle im Zusammenhang stehende Information vereint.
Isch hab da mal was vorbereided. ;)

Guck mal hier:
Java:
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

class Entry {
	private File file;
	private Color backgroundColor;

	public Entry(File file, Color backgroundColor) {
		super();
		this.file = file;
		this.backgroundColor = backgroundColor;
	}

	public Color getBackgroundColor() {
		return backgroundColor;
	}

	public File getFile() {
		return file;
	}

	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	public void setFile(File file) {
		this.file = file;
	}

}

class MyTableCellRenderer extends DefaultTableCellRenderer {
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		// do basic stuff
		Component result = super.getTableCellRendererComponent(table, value,
				isSelected, hasFocus, row, column);
		if (!(table.getModel() instanceof MyTableModel))
			return result;

		// do additional stuff
		MyTableModel tModel = (MyTableModel) table.getModel();
		Entry e = tModel.getEntries().get(row);
		setBackground(e.getBackgroundColor());
		return this;
	}
}

class MyTableModel extends AbstractTableModel {
	private final static int FILE_NAME = 0;
	private final static int PATH_NAME = 1;
	private List<Entry> entries = new ArrayList<Entry>();

	public int getColumnCount() {
		return 2;
	}

	List<Entry> getEntries() {
		return entries;
	}

	public int getRowCount() {
		return entries.size();
	}

	public Object getValueAt(int row, int column) {
		Entry e = entries.get(row);
		switch (column) {

		case FILE_NAME:
			return e.getFile().getName();
		case PATH_NAME:
			return e.getFile().getAbsoluteFile();

		default:
			/* unreachable */
			return null;
		}
	}
}

public class TestA extends JFrame {
	public static void main(String[] args) {
		new TestA().setVisible(true);
	}

	private JTable table;

	private MyTableModel mtModel;

	public TestA() {
		super();
		setLayout(new GridLayout(1, 1));
		setSize(200, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		mtModel = new MyTableModel();
		Entry e = new Entry(new File("test.txt"), new Color(255, 200, 190));
		mtModel.getEntries().add(e);
		e = new Entry(new File("blub.txt"), new Color(200, 255, 195));
		mtModel.getEntries().add(e);
		for (int i = 0; i <20; i++) {
			e = new Entry(new File(String.format("oink%d.csv", i)), new Color(
					220 + i, 220 + i, 128 + i * 4));
			mtModel.getEntries().add(e);
		}

		table = new JTable(mtModel);
		
		// ich weiß nicht ob du nicht mehrere Renderer benötigst
		// daher hab ich nur einen Object renderer registriert.
		table.setDefaultRenderer(Object.class, new MyTableCellRenderer());
		getContentPane().add(new JScrollPane(table));
	}
}

Ich hoffe ich konnte weiterhelfen
Greez Isaias
 
Zuletzt bearbeitet von einem Moderator:

Neue Beiträge

Zurück