Rzutowanie w dół

0

Witam

Mam mały problem ze zrozumieniem tego całego rzutowania w dół... w google za dużo o tym nie ma, książka Thinking in Java ujmuje to troche mało precyzyjnie ,a książka Marcina Lis-a... niby okej ale...

Mamy dwie klasy:

class Punkt
{
	public int x;
	public int y;
}

i dziedzicząca:

class Punkt3D extends Punkt
{
	public int z;
}

oraz 2 klasy main:

Pierwsza(której próba uruchomienia oraz kompilacji nie przystwarza problemu):

class MainPunkt
{
	public static void main (String [] args)
	{
		Punkt3D punkt3D1 = new Punkt3D();
		
		punkt3D1.x = 10;
		punkt3D1.y = 20;
		punkt3D1.z = 30;
		
		
		Punkt punkt = (Punkt) punkt3D1;
		
		punkt.x = 40;
		punkt.y = 50;
		
		Punkt3D punkt3D2 = (Punkt3D) punkt;
		
		punkt3D2.x = 70;
		punkt3D2.y = 80;
		punkt3D2.z = 90;
		
	}
}

oraz druga (kompilująca się bez błędów, ale pokazująca wyjątek ClassCastException):


class MainPunkt
{
	public static void main (String [] args)
	{
		Punkt punkt = new Punkt();
		
		Punkt3D punkt3D = (Punkt3D) punkt;
		
		punkt3D.z=10;
	
	}
}

I moje pytanie czemu tak się dzieje i czym różni się rzutowanie tych samych klas:

W pierwszej main:
Punkt3D punkt3D2 = (Punkt3D) punkt;

W drugiej main:
Punkt3D punkt3D = (Punkt3D) punkt;

Z góry wielkie dzięki za odpowiedź i łopatologiczne wytłumaczenie tej sytuacji... [???]

0
        Punkt3D punkt3D1 = new Punkt3D();
             
        Punkt punkt = (Punkt) punkt3D1;

Rzutowanie nie zmniejszyło obiektu, zmienna punkt ma nadal trzy pola, tylko do jednego z nich (z) nie ma aktualnie dostępu.

        Punkt punkt = new Punkt();
               
        Punkt3D punkt3D = (Punkt3D) punkt;

Rzutowanie nie jest konstruktorem, w szczególności nie dodaje pól. Zmienna punkt nie ma pola z, zatem nie można jej potraktować jako obiektu klasy Punkt3D.

0
class Punkt
{
	public int x;
	public int y;
}

class Punkt3D extends Punkt
{
	public int z;
}

Zapis ten oznacza, że klasa Punkt3D rozszerza klasę Punkt o kolejne pole typu int, czyli obiekty klasy Punkt będą posiadać dwa pola, a obiekty klasy Punkt3D będą posiadać 3 pola. Proste i zrozumiałe.
Dalej:

class MainPunkt {

	public static void main (String [] args) {

		Punkt3D punkt3D1 = new Punkt3D(); //1

		punkt3D1.x = 10;
		punkt3D1.y = 20;
		punkt3D1.z = 30;

		Punkt punkt = (Punkt) punkt3D1; //2

		punkt.x = 40;
		punkt.y = 50;

		Punkt3D punkt3D2 = (Punkt3D) punkt; //3

		punkt3D2.x = 70;
		punkt3D2.y = 80;
		punkt3D2.z = 90;
	}
}

Co tutaj się dzieje. W (1) tworzysz obiekt klasy Punkt3D, a on zgodnie z wcześniejszym komentarzem posiada 3 pola (x, y i z). W (2) tworzysz nową referencję typu Punkt oraz (za pomocą rzutowania, które nie jest potrzebne) przypisujesz jej referencję punkt3D1 (należy pamiętać, że obie referencje odnoszą się do tego samego obiektu, który posiada 3 pola). Ponieważ referencja punkt jest typu Punkt więc za jej pomocą możesz odnosić się tylko do dwóch pól (x oraz y). Dalej pamiętamy o fakcie, że referencja punkt odnosi się do obiektu typu Punkt3D, który posiada wszystkie 3 pola. W (3) tworzysz nową referencję typu Punkt3D i przypisujesz jej referencję punkt. W tym momencie rzutowanie jest potrzebne i możliwe, ponieważ oryginalny obiekt faktycznie jest typu Punkt3D i posiada wszystkie 3 pola deklarowane przez klasę.

W następnym kodzie masz coś takiego:

class MainPunkt {

	public static void main (String [] args) {

		Punkt punkt = new Punkt(); // 1
		
		Punkt3D punkt3D = (Punkt3D) punkt; // 2
		
		punkt3D.z = 10; // 3
	}
}

W (1) tworzysz obiekt klasy Punkt, który posiada dwa pola (x i y) - nic szczególnego. W (2) próbujesz za pomocą rzutowania przypisać referencję punkt do nowej referencji punkt3D, bo niby czemu miało by nie działać jak przedtem działało. Ano działało z tym, że przedtem na samym początku tworzyłeś obiekt klasy Punkt3D, a tutaj tworzysz obiekt klasy bazowej, czyli klasy Punkt.
Inaczej (nie wprost): załóżmy, że w (2) VM nie rzuciła żadnego wyjątku i jesteśmy w (3). Pamiętamy, że mimo iż mamy dwie referencje (punkt i punkt3D) to posiadamy jeden obiekt klasy Punkt. Obiekt ten ma tylko dwa pola ze względu na (1). W (3) próbujesz odwołać się do pola 'z', co jest możliwe dla kompilatora, ponieważ referencja punkt3D jest klasy Punkt3D, a ta posiada pola x, y i z. Z drugiej strony jednak obiekt do którego odnosi się referencja punkt3D nie posiada tego pola, ponieważ samo rzutowanie nie jest w stanie go stworzyć. Dochodzimy do sprzeczności.

Edit:
//up: I po co się rozpisywałem.

0

Edit:
//up: I po co się rozpisywałem.

Podam Ci pare powodów:

  1. Zrozumiałem w pełni na czym polega rzutowanie... (tzn masz u mnie duże piwo)
    2.Wiesz co oznacza słowo łopatologicznie... i oto właśnie chodzi.
    3.Bedzię wreszcie porządny artykuł na ten temat.
    4.Jak napiszesz książke.. to na pewno sprzedaz jeden egzeplarz... (ja go kupie)
    5.Kariera nauczyciela stoi przed Tobą otworem...

I to by było na tyle....

Serdeczne dzięki chłopaki.....

1 użytkowników online, w tym zalogowanych: 0, gości: 1