# Objekte über mehrere Klassen (?)



## perryrhodans (17. Dezember 2004)

Hiho Leute!

Ich habe gerade in der Schule angefangen, Java zu programmieren.
Der einfachheit halber (für ale Anfänger) nutzen wir vorerst ein Paket, das die wichtigsten Befehle beinhaltet, somit haben wir zum Beispiel einen Bildschirm und können Texte darauf ausgeben, ohne den genaueren Java-Code zu kennen.

Jedenfalls habe ich nun ein Problem (was wir bisher noch nicht besprechen):
Ich initiallisier in einer Klasse in einer Methode:
#Klasse initiallisiereAlles:

```
Bildschirm bildschirm = new Bildschirm();
Stift           stift          = new Stift();
```

#Klasse gibAllesAus:

```
initiallisiereAlles iA = new initiallisiereAlles();

iA.stift.schreibe("Breite: " +iA.bildschirm.breite() + "Hoehe: " + iA.bildschirm.hoehe());
```

Diese wird dann von der Main- Klasse aufgerufen. Alles schön und gut, ich bekomme den Bildschirm. 
Jedoch wenn ich diesen Bildschirm (z.B. um seine Größe zu ändern oder auszugeben) von einer anderen Klasse starten will, gibt es nur eine NullPointerException.
Würde ich Bildschirm immer neu deklarieren, öffnen sich auch immer wieder neue Bildschirme...
Also, ich bin noch totaler Anfänger, deswegen würde ich mich da über Hilfe freuen

Cya


----------



## Snape (18. Dezember 2004)

Ich nehme an, dass die Zeile

Stift           stift          = new Stift();

im Konstruktor ausgeführt wird. Dadurch ist die Sichtbarkeit der Variable stift außerhalb nicht mehr gegeben. So sollte es funktionieren, wenn die Klassen im gleichen package liegen. Wenn nicht, stift als public deklarieren.


```
class MyClass
{
Stift stift;
 MyClass()
 {
   stift = new Stift();
 }
}
```

Je nach Bedarf geht natürlich auch:

```
class MyClass
{
Stift stift = new Stift();
 MyClass()
 {
   // mach was
 }
}
```



Übrigens sind public Variablen i.A. verpönt, besser/sauberer sind getter/setter-Methoden.

```
private Stift stift;
public getStift()
{
 return stift;
}
```

Um dann in der anderen Klasse so darauf zuzugreifen:

```
iA.getStift().schreibe("kungFoo");
```


----------



## perryrhodans (18. Dezember 2004)

Hm, ich glaube, mien Problem wurd enicht so ganz verstanden, 
okay, habe es auch ein wenig schlecht erklärt.
Also, zweiter Versuch (aber vielen Dank Snape  ):

Hier habe ich die Startklasse:

```
package testmitklassen;

public class StartTest {
  public StartTest() {
  }

  public static void main(String[] args) {
    StartTest startTest1 = new StartTest();

    TestFunktionEins tFE = new TestFunktionEins();

    tFE.getbildschirminfos();
  }
}
```

So, von hier aus funktioniert ja alles, also die Aufrufe.
Weiter habe ich dann hier die Anwendungsklasse (in der  die benötigten Komponenten
wie bildschirm und Stift initiallisiert werden):

```
package testmitklassen;
import stiftUndCo.*;

public class TestAnwendung {

  private Bildschirm bildschirm = new Bildschirm();
  // diese Klasse darf nur einmal aufgerufen werden, da er ja sonst wieder einen neuen
  // Bildschirm erstellt... das will ich ja nicht, habe aber keine Lösung dafür
  private Stift stift;
  //okay, mit dem Stift alles fein, nur habe ich ihn doch dann nicht mit new initiallisiert?!
  // heißt doch, er existiert noch nicht wirklich

  public TestAnwendung() {
    return stift;      // -> Meldung: cannot return a value from method whose result
                         //                    type is void 
  }
}
```

Ich denke, hier besteht mein größtes Problem. 
Da ich auch nicht wirklich verstand, was Snape meinte.
Heisst das, dass ich die Objekte im Konstruktor erstellen soll? 
Funktionier irgentwie nicht so, keine Ahnung wie es sonst geht.
Zweites Problem, ich kann in initiallisiereAlle -> (iA) keinen Konstruktor
namens getStift() erstellen, ab dann sagt er: invalid method declaration; return type required

Puh, ich bin echt fertig, habe schon so viel versucht, klappt alles nicht.
Bitte bitte helft mir. *verzweifelt sei*

Übrigens, noch der Code, von dem ich dann die Bildschirminformationen erfrage:
Klasse TestFunktionEins:

```
package testmitklassen;
import stiftUndCo.*;

public class TestFunktionEins {
  public TestFunktionEins() {
  }
  TestAnwendung tA = new TestAnwendung();

  public void getbildschirminfos(){
   tA.stift.schreibe("Breite: " +tA.bildschirm.breite() + "Hoehe: " + tA.bildschirm.hoehe());
  }

}
```


Vielen Dank!

Cya
-PerryRhodans-


----------



## RedWing (18. Dezember 2004)

> ```
> public TestAnwendung() {
> return stift;      // -> Meldung: cannot return a value from method whose result
> //                    type is void
> ...



Ein Konstruktor kann keinen Wert via return zurückgeben bzw er kann auf 
keine Weise einen Wert zurückliefern... Wie du diesen return value 
umgehen kannst und  das mit deiner Stiftproblematik hat Snape schon ganz gut 
erklärt denke ich...




> // diese Klasse darf nur einmal aufgerufen werden, da er ja sonst wieder einen neuen
> // Bildschirm erstellt... das will ich ja nicht, habe aber keine Lösung dafür



Wozu mehrmals aufrufen bzw meherere Objekte davon erzeugen?
Das brauchst du ja gar nicht...
Du übergibst dein Objekt tA einfach sämtlichen Methoden mit denen du was mit
tA anstellen willst:

```
class MyClass{
  ...
  public void doSomething(TestAnwendung tA){
      System.out.println("Breite: " +tA.bildschirm.breite() + "Hoehe: " + tA.bildschirm.hoehe());
  }
   ...
}
```

Aufruf:


```
package testmitklassen;
import stiftUndCo.*;

public class TestFunktionEins {
  public TestFunktionEins() {
  }
  MyClass c = new MyClass();
  TestAnwendung tA = new TestAnwendung();
   c.doSomething(tA);

  public void getbildschirminfos(){
   tA.stift.schreibe("Breite: " +tA.bildschirm.breite() + "Hoehe: " + tA.bildschirm.hoehe());
  }

}
```


----------



## perryrhodans (18. Dezember 2004)

Okay, bis jetzt konnte ich das alles nachvollziehen.
Doch wie sollte meine TestAnwendung- Klasse aussehen, also die, wo Bildschirm und Stift initiallisiert werden? 
Und kleine Hilfe, dieses *public getStift(){return Stift}*, was ist das eigentlich?
Und wo kommt das überhaupt hin? 

Vielen Dank nochmal für die Hilfe, bis jetzt habt ihr mich schon ein gutes Stück weiter gebracht!

Cya

PS. Ooooookay, es funktioniert. Mal sehen,immo sieht es noch ein wenig zu krumm aus alles, aber ich werde mal ein wenig damit rumspielen und  mich da reinarbeiten!
Vielen vielen Dank!


----------



## RedWing (18. Dezember 2004)

perryrhodans hat gesagt.:
			
		

> Und kleine Hilfe, dieses public getStift(){return Stift}, was ist das eigentlich?





			
				snape hat gesagt.:
			
		

> Übrigens sind public Variablen i.A. verpönt, besser/sauberer sind getter/setter-Methoden.



public, private, protected sind Zugriffsmechanismen für Klassenmember.
private = nur in Klasse sichtbar
public = überall sichtbar
protected = in Klasse und allen Subklassen sichtbar

Klassenmembers wie dein stift Object sollten aus Sicherheitsgründen damit sie nicht
jeder verändern kann private in deiner Klasse gekapselt werden.
Da du aber jetzt auf diese von andren Klassen kein Zugriff mehr hast, da sie ja 
private ist, kann man diese Zugriffsrechte sozusagen feineinstellen in dem
man sich Methoden in der Klasse definiert die einen lesenden und/oder 
schreibenden Zugriff auf deine Klassenmember stift definieren. Solche Methoden
heissen getter/setter Methoden.


```
public getStift(){return Stift}
```
  bietet dir somit einen lesenden
Zugriff auf deine als private deklarierte Klassenmember stift.
Desweiteren befindet sie sich in der Klasse TestAnwendung da ja dein Stift
Objekt ein Member gerade dieser Klasse ist...



> Doch wie sollte meine TestAnwendung- Klasse aussehen, also die, wo Bildschirm und Stift initiallisiert werden?



Auch das hat Snape eigentlich schon beantwortet. Konkret für deinen 
Fall könnte es vielleicht so aussehen:


```
package testmitklassen;
import stiftUndCo.*;

public class TestAnwendung {

  private Bildschirm bildschirm;
  private Stift stift;

  public TestAnwendung() {  //Konstruktor erschafft und initialisiert Klassenmembers
    bildschirm = new Bildschirm();
     stift = new Stift();
  }
   
   public Stift getStift(){ return stift; } //ermoeglicht lesenden Zugriff auf Stift da er von aussen nicht sichtbar ist
   public Bildschirm getBildschirm(){ return bilschirm; } // dito 
}
```

Gruß

RedWing


----------



## perryrhodans (18. Dezember 2004)

Uuund hops... da habe ich einen großen Sprung gemacht!
Vielen Dank RedWing, nun habe ich so einiges gelernt und es funktioniert auch alles FAST so wie ich will. 

Leider habe ich trotzdem noch ein  Problem... 

Ich kann den Stift zum Beispiel bewegen, ich kann den Bildschirm neu dimensionieren und auch seine Werte ausgeben, jedoch nicht schreiben, bzw. irgentwas, was
mit zeichnen auf dem Bildschirm zu tun hat...

Es wird immer eine NullPointerException ausgegeben

Hier habe ich einmal TestAnwendung, wo alle deklariert werden, nach dem Muster:


```
package testmitklassen;
import stiftUndCo.*;

class TestAnwendung {
  private Stift stift;
  private Bildschirm bildschirm;

   TestAnwendung()
   {
     stift = new Stift();
     bildschirm = new Bildschirm(500,200);
   }

   public Stift getStift(){return stift;}
   public Bildschirm getBildschirm() {return bildschirm;}
}
```


Ich habe das alles verstanden *freu* 

So, nun die Ausführung in TestFunktionEins:


```
package testmitklassen;

public class TestFunktionEins {
  public TestFunktionEins() {
  }

  public void getbildschirminfos(TestAnwendung tA){
    System.out.println("Hoehe: " + tA.getBildschirm().hoehe()); //funktioniert
    System.out.println("Breite: " + tA.getBildschirm().breite());   //funktioniert
    tA.getStift().runter();                       //sagt der nichts zu, denke, funktioniert auch
    tA.getStift().schreibe("abc");           //java.lang.NullPointerException
  }
}
```

Anstatt zu Schreiben könnte man auch Linien oder Kreise malen, immer die gleiche Meldung. 
Diese Methode wird von der main-Klasse aus gestartet.
Habt ihr ne Ahnung woher das kommt? (bzw. nichts kommt)


Hey, ich habe heute soviel gelernt, *gg* das ist klasse.

Cya
-Perry-


----------



## RedWing (18. Dezember 2004)

Hi,
also so wie du es beschrieben hast kann ich da jetzt keinen Fehler erkennen.

Wie rufst du die Methode denn auf?

Ein möglicher Fall könnte so aussehen:


```
TestFunktionEins tF = new TestFunktionEins();
TestAnwendung tA = new TestAnwendung();
tF.getbildschirminfos(tA);
```

sollte eigentlich funktionieren, aber vielleicht kannst du dein Programm auch mal
als zip mit anhängen...

Gruß

RedWing


----------



## perryrhodans (18. Dezember 2004)

Ja, genau so rufe ich das auf. 

Mom, das Script habe ich hier.

Fast 7kb, also nichts. 

Mal schauen, ob du doch noch was findest *hoff*

Cya


----------



## RedWing (18. Dezember 2004)

Hallo,
du hast mir nur die *.class Dateien geschickt...

Gruß

RedWing


----------



## perryrhodans (18. Dezember 2004)

*kopfkratz*
Also, im Zip- File sollten eigentlich der Ordner Classes und SRC sein und 
TestMitKlassen.jpx.
Nichts im Ordner SRC drin?

Cya

Und hier noch stiftUndCo:


----------



## RedWing (18. Dezember 2004)

Hi, sorry hab ich übersehen.
Allerdings kann ich dein package stiftundco nicht finden und somit dein 
Programm nicht übersetzen hast du vielleicht icq o. msn?

//edit ah danke
Gruß

RedWing


----------



## RedWing (18. Dezember 2004)

Hallo,
das Problem war nicht, deine Anwendung für sich sondern du hast deine 
Bibliothekn stiftundco falsch angewendet..

Und zwar im Konstruktor TestAndwendung:


```
TestAnwendung()
   {
     bildschirm = new Bildschirm(500,200); 
     stift = new Stift();
     tastatur = new Tastatur();
     maus = new Maus();
     hilfe = new Hilfe();
   }
```

nicht so:

```
TestAnwendung()
   {

     stift = new Stift();
     bildschirm = new Bildschirm(500,200); 
     tastatur = new Tastatur();
     maus = new Maus();
     hilfe = new Hilfe();
   }
```

Das Problem ist das in deiner Bilbliothek in der Klasse Bildschirm eine neue 
Klassenmember mit dem erschaffen wird, die irgendwie in deiner Bibliotheksklasse
Stift in der Methode Schreibe verwendet wird aber vorher im Konstruktor von Stift
auf eine neue Klassenmember von Stift zugewiesen wird aber nur wenn diese 
!= null ist..
Wenn du  nun stift vor bildschrim erschaffst, 
ist die besagte Klassenmember von Bildschirm noch null und diese 
Klassenmember kann somit im Stiftkonstruktor nicht zugwiesen werden.
Etwas kompliziert erlärt vielleicht erklärt es der Code aus deiner lib besser:

Stiftkonstrulktor:

```
public Stift(){
        if (DasFenster.hauptFenster != null)
                {    
                        kenntBi=DasFenster.hauptFenster;                     
        } 
        this.setzeStandard();
  }
```
DasFenster.hauptFenster ist zu dem Zeitpunt noch null...
Schreibemethode:

```
public void schreibe(String ps)
  {
        gr=kenntBi.aktuellerGrafikkontext(); //NUllpointer Exception
        setzeZustand(gr);

        if (gr != null) {

        gr.drawString(ps,(int)Math.round(zstiftx),(int)Math.round(zstifty));

        //kenntBi.repaint();
        zstiftx=zstiftx+gr.getFontMetrics().stringWidth(ps);

        }
        gr = null;
  }
```

Hier passierts kentBi is null, somit tritt eine Speicherzugriffsverletzung auf...

Lange Rede kurzer Sinn:
Bevor du die Lib stiftUndCo anwendest guck dir vorher immer die Doku genau
an, und ziehe auch eventuelle Bsp mit ein die vielleicht in der Doku die
Anwendung dieser Erklären...

Gruß

RedWing


----------



## perryrhodans (18. Dezember 2004)

*rofl* 
Neeein, das ist doch nicht wahr. 
So ein kleiner Fehler, aber darauf erstmal zu kommen, nicht schlecht, meinen Respekt!
*knuuutsch* Boh, ich liebe dich. 

Puh *tief durchatme*

Also, ich habe heute von Snape und vor allem von die sehr sehr viel gelernt.
Ich bin dir echt total dankbar.
Ich werde nun öfters mal in die Einzelheiten des stiftUndCo- Pakets schauen, um die Fehler auch selber zu finden, falls es welche gibt.

Nochmal herzlichen Dank, nun funktioniert es auch bei mir, alles top.

Krass, echt, sone Kleinigkeit, hehe, unglaublich.

So, jetzt wird erstmal auf einem neuen Niveau programmiert 

Dankeschöööön


Cya
-Perry-


----------

