Durch alle Attribute eines Objektes iterieren

krx

Mitglied
Hallo,

ich habe Methoden, die für alle Attribute eines Objektes angewendet werden sollen - z.B. (!) die Prüfung, ob irgendein Attribut null ist. Ich will nun aber nicht 10x schreiben müssen
Java:
obj.isNull(attribut);
Ich dachte, ich mache mir ein mal eine Hashtable mit allen Attributen des Objektes:
Java:
Hashtable hashtable = new Hashtable();
hashtable.put("name attribut 1", this.attribut1);
...
hashtable.put("name attribut 10", this.attribut10);
Und dann kann ich durch diese Hashtable iterieren und meine Methoden ausführen, die alle Attribute betreffen.
Das Problem ist, wie ich gemerkt habe, dass die Attribute in der Hashtable keine Referenz zu den Attributen des eigentlichen Objektes haben. Das heißt, wenn ich in der Hashtable eine Value ändere, ändert sich nicht das Attribut des Objektes.

Hat jemand eine Lösung oder einen ganz anderen Ansatz?
 
ja ... sowas geht mit reflections ... du holst dir ein objekt .. davon die klasse ... darüber die variablen und prüfst im objekt-kontext auf inhalt ...

ist aber schlechtes design ...

mir würde zwar jetzt weniger ein grund einfallen warum man auf NULL prüfen sollte ... aber wenn man datenkapselung richtig anwendet muss man halt für jede variable getter und setter schreiben ... und wenn die klasse ein paar viele variablen hat muss man auch ein paar mehr methoden schreiben ...
 
Das Stichwort heißt Reflection... alternativ kannst du auch org.apache.commons.beanutils.BeanUtilsBean von apache commons benutzen...
 
Das mit dem Speichern der Attribute in einem HashTable klappt nicht, weil Du eine Referenz auf das Attribut speicherst, wenn nicht-primitiv ist, bzw. den Wert, wenn es primitiv ist (int, char etc.). Wenn danach jemand den wirklichen Attributwert mit einer neuen Referenz belegt bzw dessen Wert ändert, steht in der Map ein veralteter Wert. Die sauberste Lösung wäre eine Methode mit Namen z.B. "validateState():
Java:
// Methode in der Klasse, deren Attribute validiert werden sollen.
public void validateState() {
  if(obj1 == null) {
    throw new NullpointerException("Attribut 'obj1' darf nicht null sein.");
  }
  if(obj2 < 0) {
    throw new IllegalArgumentException("Attribut 'obj2' mus >= 0 sein.");
  }
  ...
}
Da schreibst Du zwar die Prüfungen erstmal hin. Aber nur einmal und die Methode kannst Du dann von überall aufrufen. Ein etwas allgemeinerer Ansatz wäre Reflection/Introspection. Aber davon rate ich hier ab.
 
Zuletzt bearbeitet von einem Moderator:
Über reflect funktioniert das super:

Java:
		try {
			Haus haus = new Haus("bla","bla");

			for (Field field : Haus.class.getDeclaredFields()) {
				field.setAccessible(true);
				System.out.println(field.getName() + ": " + (f.get(haus) == null)); // haus ist hier dann dein Object (bei dir dann this)
			}
		} catch (Exception ex) {
			System.out.println(ex.getMessage());
		}

sollte alle Variablen von Haus auf null überprüfen und ausgeben
 
Den Code von anti-held in die von mir vorgeschlagene validateState()-Methode der zu validierenden Klasse und es müsste direkt funktionieren, auch ohne, dass man eigentlich private Felder mit:
Java:
field.setAccessible(true);
zugreifbar machen muss. Habe es nicht ausprobiert, aber es wäre einen Versuch wert.
 
Hallo krx,

ich bin zwar auch noch ein Newbie in JAVA, aber ein Merksatz hat sich mir schon eingeprägt:

Wenn du an einer bestehenden Klasse (--> Objekt) etwas ändern willst, dann überschreibe sie einfach 😉

Was das heißt, demonstriere ich an einem Beispiel, das ich vor kurzem erstellt habe. Ich musste 49 Buttons in einen Frame bzw. seinen contentpane einbetten, für die ich einige Attribute ändern wollte. Also habe ich eine eigene Klasse erstellt, die ich von JButton erben ließ.

Java:
package pFormDotComsVersenken;

import java.awt.Font;
import javax.swing.JButton;

/**
 * Die Klasse ändert Attribute für JButtons und gibt 
 * das geänderte Objekt zurück
 */
 public class DCVButton extends JButton {
//	Enumeration, um aus Buchstaben die x-Position abzuleiten
	public enum LetterNumbers {
		A (10),
		B (58),
		C (106),
		D (154),
		E (202),
		F (250),
		G (298);
		
		private int xPos;
		
		private LetterNumbers(int pos){
			xPos = pos;
		}
		public int getXPos(){
			return xPos;
		}
	}
	
	private int myY=0;	// Für die y-Position jeden Buttons
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -1139222144343874492L;

//	Konstruktor. Hier lege ich die Attribute fest (Font, Bounds(x,y,width,height)
//	Den x-Wert hole ich aus der enum (z. B. A = 10, B = 58 usw.)
//	Der Text, der übergeben wird, sieht z. B. so aus: "A1" oder "G4"
	public DCVButton(String Text) {
		Font f1 = new Font("Arial", Font.BOLD, 10);
		this.setFont(f1);
		this.setText(Text);
		this.setBounds(LetterNumbers.valueOf(Text.substring(0,1)).getXPos(), 
				getMyY(Integer.parseInt(Text.substring(1))),48,25);
	}
	
//	Hieraus kommt der y-Wert
	public int getMyY(int zeile) {
		switch(zeile){
		case 1:
			myY=25;break;
		case 2:
			myY=50;break;
		case 3:
			myY=75;break;
		case 4:
			myY=100;break;
		case 5:
			myY=125;break;
		case 6:
			myY=150;break;
		case 7:
			myY=175;break;
		default:
			myY=25;
		}
		return myY;
	}
	
}

In der aufrufenden Klasse sieht das so aus:

Java:
...
		String[] buc = {"A","B","C","D","E","F","G"}; //Buchstaben für Benennung der Buttons
		myButtons = new DCVButton[49];
		MyMouseListener mml = new MyMouseListener(this);

		for(String b:buc){
			for(int i = 1;i<8;i++){
				myButtons[i] = new DCVButton(b+String.valueOf(i));
				myButtons[i].setName("btn"+b+String.valueOf(i));
				myButtons[i].addMouseListener(mml);

				contentPane.add(myButtons[i]);
			}
		}
...

Noch Fragen?

Viele Grüße
JavaInBrain
 

Neue Themen


Zurück
Oben