PDA

View Full Version : [JAVA] un dubbio o mistero da sfatare


Pagine : 1 [2]

recoil
11-02-2004, 22:53
Originariamente inviato da misterx
ah, quindi c'è differenza tra compilatore e JVM

è come dire che se riuscissi ad imbrogliare il compilatore riuscirei ad usare il metofo getlato() anche se implementato solo nella classe cubo ?

ma come lo imbrogli il compilatore?

misterx
12-02-2004, 08:53
imbrogli è un modo di dire

quello che cerco di sottolineare è che se scrivi:


Object o = new Cubo(10);

e poi

System.out.println( ((Cubo)o).tostring() );

o scrivi

System.out.println( o.tostring() );

la JVM se ne frga in quanto usa prima il metodo toString() presente nella classe dell'oggetto istanziato

quindi, che gli frega al compilatore di andare a vedere se in Object esiste o no un metodo getlato() ?

se il compilatore guarda nella classe Cubo() di sicuro lo trova quindi non sembra aver senso il controllo che fa

non so se sono riuscito a farmi capire

misterx
12-02-2004, 14:46
ho due classi A e B

class B extends A

in questo caso sono obbligato ad istanziare un oggetto di tipo B, col costruttore di A usando super() ?

io ho provato senza "super" ma non compilo...mah

recoil
12-02-2004, 14:56
Originariamente inviato da misterx
ho due classi A e B

class B extends A

in questo caso sono obbligato ad istanziare un oggetto di tipo B, col costruttore di A usando super() ?

io ho provato senza "super" ma non compilo...mah

non ho ben capito il problema

misterx
12-02-2004, 16:18
dicevo: ho una classe scritta da tizio di nome Parallelepipedo, io ora desidero scrivere la classe Cubo; osservando ciò che fa Parallelepipedo, mi accorgo che posso usare alcuni dei suoi metodi senza riscriverli quindi mi accingo a scrivere:

pubic class Cubo extends Prallelepipedo{

......
......
}

però accade questo fatto:

se io ora scrivo:


Parallelepipedo p = new Cubo(10);

e nella mia classe Cubo ho il seguente costruttore:

pubic class Cubo extends Prallelepipedo{
double lato;

public Cubo(double l){
lato = l;
}
..........................
}


il compilatore non compila ma segnala errore; funziona se scrivo:

pubic class Cubo extends Prallelepipedo{
double lato;

public Cubo(double l){
super(l,l);
}
..........................
}



domanda: perchè i è obbligati a farsi costruire un Cubo dalla superclasse ?

spero di essere stato chiaro questa volta :)

PGI
12-02-2004, 18:56
A) Si è sempre, e non solo nel caso da te citato, responsabili della corretta inizializzazione delle superclassi.

Per comodità, il compilatore è impostato per aggiungere automaticamente (nel file class) un richiamo al costruttore vuoto della superclasse, nel caso in cui il programmatore non abbia definito da solo un percorso di inizializzazione. Evidentemente, se la superclasse non ha un cotruttore vuoto -> zappete, il compilatore "si lagna".

Non sei obbligato a richiamare il costruttore della superclasse più di quanto non lo saresti stato se la superclasse avesse avuto un costruttore vuoto, solo che nel primo caso devi fare un richiamo esplicito: in ogni caso le sotto-classi sono obbligate a richiamare il costruttore delle super-classi.

B) Le superclassi non inizializzano le sottoclassi. Le sottoclassi non inizializzano le superclassi. Le classi definiscono le procedure per inizializzare sè stesse e stop. Le sottoclassi "fagocitano" le procedure definite nel costruttore delle superclassi all'interno del proprio costruttore, ma questo non significa che per avere un oggetto Cubo la macchina virtuale ne debba prima creare uno Parallelepipedo: Cubo "si inizializza da sè".

misterx
12-02-2004, 19:01
tu dici: in ogni caso le sotto-classi sono obbligate a richiamare il costruttore delle super-classi ma a quale scopo ?

a me è stato detto che è un comportamento predefinito ed una sottoclasse si fa aiutare sempre dalla superclasse per istanziare un suo oggetto

nel caso addirittura di:

A
|
B
|
C
|
D

istanzi un oggetto di tip D, si attiva la catena di creazione sino ad Object

D chiama il costruttore di C, C quello di B, B quello di A, A quello di Object

boh, forse per collegarci i metodi ereditati

PGI
12-02-2004, 20:05
Originariamente inviato da misterx
boh, forse per collegarci i metodi ereditati

Questo non è ragionevole. Sarebbe una duplicazione, essendo i metodi erediti "caricati" quando la classe è inizializzata (cioè prima che venga invocato il costruttore).

Avevo già fatto l'esempio del JFrame (non dev'essere stato molto significativo :D)

Occorre pensare allo scopo del costruttore: definire quelle procedure "essenziali" affinchè l'oggetto sia pronto ad essere usato. (tecnicamente il costruttore è responsabile dell'inizializzazione della classe, ma "filosoficamente" esiste per il motivo citato).

Se A ha uno scopo, allora il suo costruttore definisce quelle procedure essenziali affinchè la creazione di un oggetto di tipo A restituisca un elemento funzionale.

Se B estende A, è illogico che la creazione di un oggetto B restituisca qualcosa che sia "meno che A": ecco perchè il costruttore può essere sovrascritto, come i metodi comuni, ma non può non richiamare almeno una delle procedure di inizializzazione del genitore, che viene eseguita prima delle istruzioni definite dalla costruttore della sottoclasse.

Ereditare metodi e campi può essere visto come un problema di "forma": B eredita da A il metodo M, può ereditarlo "così com'è" o cambiarne il contenuto fino al punto di privarlo di effetti.

Per il costruttore conta la sostanza: B ha un costruttore il cui contenuto è per forza almeno uno di quelli di A.

misterx
12-02-2004, 20:24
Originariamente inviato da PGI


public class Prova extends JFrame {
public Prova() {
//TA DAH!
}
}



Che succede in quel "Prova()"? Se non fosse garantito il percorso di inizializzazione della superclasse JFrame, a Prova mancherebbero tutte le operazioni compiute dal costruttore di JFrame



ecco il motivo: ma cazzarola, come fanno a sfuggirmi cose così ? :muro:


se io istanzio un oggetto di una sottoclasse per forza di cose devo inizializzare anche la superclasse altrimenti come cacchio uso i suoi metodi ?

azzo che pirla....


però pensavo che fosse quell'extends a risolvere tutto

PGI
12-02-2004, 21:16
Sei fuori strada.

Originariamente inviato da misterx
se io istanzio un oggetto di una sottoclasse per forza di cose devo inizializzare anche la superclasse altrimenti come cacchio uso i suoi metodi ?

Li usi a prescindere dal costruttore perchè..

però pensavo che fosse quell'extends a risolvere tutto
...pensavi giusto. Il "collegamento" ai metodi ereditati è risolto esclusivamente in virtù della clausola extends.

misterx
12-02-2004, 21:24
allora non ci siamo

se extends lavora per me, a che serve super() ?

uno dei 2 è ridondante

PGI
12-02-2004, 22:42
super() fa chiaramente qualcosa che extends non fa, cioè "infila" nel costruttore della sottoclasse le istruzioni "scritte" nel costruttore della superclasse.

misterx
13-02-2004, 14:12
cionci, è possibile avere questa discussione in un unico file ?


:)

misterx
13-02-2004, 15:25
un esempio completo per le eccezioni controllate
Praticamente qui il compilatore ci obbliga a trattare le eccezioni che vengono già reputate sollevabili.
Qui, ho le gestiamo (try/catch) oppure le deleghiamo (throws)

PGI, è così la storia vero ?

scusa ma sto ripassando :D



import java.io.*;

public class Eccezioni {

public static void main(String [] args) {

int c;

InputStream in = new FileInputStream(args[0]);
OutputStream out = new FileOutputStream(args[1]);

while( (c=in.read()) != -1)
out.write(c);

in.close();
}
}

PGI
13-02-2004, 15:46
E' giusto. Nel caso del codice postato sei "alla canna del gas", non puoi più delegare la gestione dell'eccezione, devi intercettarla lì.

misterx
13-02-2004, 17:49
Originariamente inviato da PGI
E' giusto. Nel caso del codice postato sei "alla canna del gas......


:D:D:D:D

ora ho capito cosa intendevi dirmi la volta scorsa, vabbè, molto scorsa, sull'essere costretti a riempire il codice di try/catch throws se quei benedetti padri di java non ti inplementavano le eccezioni non controllate :)

misterx
14-02-2004, 10:31
Parallelepipedo
|
|
Cubo


che senso ha scrivere:

Parallelepipedo p;
Cubo c;

q = (Cubo)p;

---------------------------------------------------------------------------
cqm, quello che dicevo qualche post fa e temo non sia stato compreso xchè espresso male da me :D è il comportamento diverso tra il copilatore e la JVM

se ho una classe Cane() nella quale è presente il metodo getPeso() e scrivo:

Object o = new Cane();

o.getPeso();

viene generato un errore in fase di compilazione perchè nella classe Object non è definito un metodo getPeso() ma, se ora ipotizziamo di implementare anche nella classe Object getPeso() tutto viene compilato in modo corretto

quando il codice viene eseguito, la JVM alla chiamata

o.getPeso()

userà il metodo contenuto nella classe Cane()

ma sarà pirla eh ???? :D:D:D


come, se è presente nella classe di cui istanziol'oggetto al compilatore non frega una cippa, se la implemento anche in Object accontento il compilatore ma la JVM la ignora


posso???


MAH...................

PGI
14-02-2004, 13:40
Qui sono in ballo le "norme" dell'ereditarietà, per la macchina virtuale è tecnicamente indifferente che la chiamata operi in favore del metodo della sottoclasse o della superclasse (tanto che è possibile effettuare da una sottoclasse un rinvio esplicito ad ogni campo/metodo accessibile dall'esterno della classe usando la parola chiave super)

misterx
14-02-2004, 19:36
ok PGI, ma ti sembra un comportamento corretto ?

io lo trovo alquanto nascosto e depistante :cool:

PGI
14-02-2004, 20:03
Beh, a me sembra corretto. Se crei un oggetto di tipo B, ti aspetti che si comporti come uno di tipo B, non come un A (superclasse).

misterx
14-02-2004, 20:17
saranno tutti gli esempi strani che trovo a creare scompiglio :D

Object o;
Cubo c;

o = c;

c = (Cubo)o; -----> funziona ma ha senso ?

ed ora non funziona più:

o = new Object();
c = (Cubo)o; ------> ClassCastException



Object o = new Cubo(10); -----> perfetto me se voglio accedere ad un metodo di Cubo usando come tipo riferimento Object meglio usare un bel cast "cast"

PGI
14-02-2004, 21:40
Il cast esplicito è un'operazione a rischio, per questo di solito si evita.

Per quanto riguarda i vari passaggio o-c che hai segnalato, (a parte il fatto un'esempio tanto astratto in genere fa più confusione che altro :confused: ), non ci vedo stranezze.

Object o;
Cubo c;

o = c; (Per il compilatore adesso o punta ad un Cubo);

c = (Cubo)o; (Cast esplicito da o che punta a Cubo, tutto ok).

Non solo ha senso, ma (pre 1.5) era una tappa obbligata usando gli oggetti Collection (che contenevano riferimenti Object).

e' chiaro però che se o punta ad un Object, non è più compatibile in assegnamento con un Cubo:

o = new Object();
c = (Cubo)o;

speedwago
15-02-2004, 03:07
Originariamente inviato da misterx

Parallelepipedo
|
|
Cubo


che senso ha scrivere:

Parallelepipedo p;
Cubo c;

q = (Cubo)p;

---------------------------------------------------------------------------
cqm, quello che dicevo qualche post fa e temo non sia stato compreso xchè espresso male da me :D è il comportamento diverso tra il copilatore e la JVM

se ho una classe Cane() nella quale è presente il metodo getPeso() e scrivo:

Object o = new Cane();

o.getPeso();

viene generato un errore in fase di compilazione perchè nella classe Object non è definito un metodo getPeso() ma, se ora ipotizziamo di implementare anche nella classe Object getPeso() tutto viene compilato in modo corretto

quando il codice viene eseguito, la JVM alla chiamata

o.getPeso()

userà il metodo contenuto nella classe Cane()

ma sarà pirla eh ???? :D:D:D


come, se è presente nella classe di cui istanziol'oggetto al compilatore non frega una cippa, se la implemento anche in Object accontento il compilatore ma la JVM la ignora


posso???


MAH...................

allora la cosa funziona in questo modo...
supponiamo di avere un classe employee e una sua sottoclasse manager.

employee ha nome cognome e stipendio
manager ha nome e cognome stipendio e bonus
ora se vogliamo fare un array di impegati
Employee[] e=new Emplolyee[10];
questo array puo' contenere sia manager che employee..
quindi una cosa del genere funziona
e[0]=new Emplyee();
e[1]=new Manager();

ora supponiamo che sia manager e employee hanno un metodo toString che stampi il valore di tutti i campi dell'istanza e supponiamo di mettere tutto in un cliclo di for
for(int i=0;i<e.length;i++)
e[i].toString();

l'iesimo elemento chiama tostring si emplyeee in caso di oggetto employee e tostring di manager in caso di manager...
la cosa appare chiara:
-non e' permesso chiamare metodi esclusivi di manager per oggetti istanziati in quel modo perche' altrimenti l'invocazione potrebbe fallire (esempio se toString fosse solo di Manager ...)
-se il metodo e' presente sia in sottoclasse che in superclasse viene invocato quella della sottoclasse....mi pare ovvio... nel mio esampio e' corretto che toString stampi il campo bonus quando vede che si tratta di manager...

misterx
15-02-2004, 09:57
PGI, possibile che byte e short gli facciano schifo ? :D


class Prova{
public static void main(String[] args){
System.out.println( SceltaDelMetodoDaEseguire.visualizza(1) );
}
}




class SceltaDelMetodoDaEseguire {

public static String visualizza( byte num){
return "ho scelto byte";
}

public static String visualizza( short num){
return "ho scelto short";
}

public static String visualizza( int num){
return "ho scelto int";
}

public static String visualizza( long num){
return "ho scelto long";
}
}

PGI
15-02-2004, 13:04
Concordo con l'esempio di speedwago.

Gli short.

Non è che gli piacciano molto in effetti.

In java i letterli numerici sono di tipo int o double (1 -> int, 1.0 -> double).

Con short, byte e char ci fai poco, a parte inviarli attraverso degli stream.

Per i calcoli, semplicemente tutto quello che è "meno di int" non esiste. Ad esempio:

short x = 1;
short y = 2;

short sum = x + y; <- errore.

Non esistono operazioni matematiche su short, byte, char. x e y vengono caricati nella pila degli operandi come "int", viene fatta una somma tra int e poi, per reinfilare il tutto in uno short, occorre una conversione stretta

short sum = (short) (x + y).

idem per byte e char.

double, long, e float hanno invece operatori propri.

long x = 10;
long y = 10;

long sum = x + y; <- tutto ok.

Si è portati a pensare che sia tutto ok perchè le conversioni larghe non generano mai problemi (tra interi almeno): x +y sarebbe un int che poi viene "allargato" a long.
Non è così.
Esiste un "+" dedicato alle operazioni tra "long" (e float e double), nella pila degli operandi vengono effettivamente caricati due long, sommati come long ed il valore restituito è ancora un long.

misterx
15-02-2004, 13:31
ops:)

a2000
16-02-2004, 13:36
misterx, bauscia, ojurduì mi vegne siù a Milan forever
ti aspeti a la staziun M3 de Rogoredi.

saludi e te impantana no, fa il bravo nè, mi racumandi !

:D :)

misterx
16-02-2004, 13:47
Originariamente inviato da a2000
misterx, bauscia, ojurduì mi vegne siù a Milan forever
ti aspeti a la staziun M3 de Rogoredi.

saludi e te impantana no, fa il bravo nè, mi racumandi !

:D :)


xchè mischi:D "milanese maccheronico" col francese ?

lascia perdere le derivazioni, sono tutte balle :D:D:D

mo va?

vieni a Milano x sempre ?

e come mai ? :)

devi forse inventare qualche miscuglio per abbattere lo smog? :wtf:

:asd:

misterx
19-02-2004, 11:56
ragazzi non è la mia giornata, dove cavolo sbaglio che mi entra in loop ?



public class ProvaComparable {

public static void main(String[] args) {

Cubo a = new Cubo(100);
Cubo b = new Cubo(10);

if( a.compareTo(b) > 0 )
System.out.println("il cubo a è maggiore del cubo b");
else
System.out.println("il cubo a non è maggiore del cubo b");
}
}

class Cubo implements Comparable {

double l;

public Cubo( double lato){
l = lato;
}

public int compareTo(Object o) {
return this.compareTo(o);
}

public double getlato(){
return l;
}
}

PGI
19-02-2004, 12:47
public int compareTo(Object o) {
return this.compareTo(o);
}


Questo è ricorsivo, "senza possibilità di scampo".

misterx
19-02-2004, 12:57
mi sono risvegliato :D



public int compareTo(Object o) {
if (this.getlato() > ((Cubo)o).getlato() )
return 1;
else if (this.getlato() < ((Cubo)o).getlato() )
return -1;
else
return 0;
}

PGI
19-02-2004, 15:58
Potenzinterra, usiamo le parentesi graffe per gli "if"!

http://java.sun.com/docs/codeconv/

misterx
19-02-2004, 19:26
il metodo equals non funziona e so anche il perchè ma non so perchè viene sempre natuarale scriverlo così :muro:



class Scheda{
public static void main(String[] args){

Cliente obj1 = new Cliente("Galli","Massimo","Manzoni",18);
Cliente obj2 = new Cliente("Galli","Massimo","Manzoni",18);

if (obj1.equals(obj2) )
System.out.println("vero");
else
System.out.println("falso");
}
}

class Cliente{
String cognome;
String nome;
String via;
int numero;


public Cliente(String c , String n , String v , int num){
cognome = c;
nome = n;
via = v;
numero = num;
}

}

PGI
19-02-2004, 19:55
ehm...potrei sbagliarmi ma a me sembra che in Cliente di metodi "equals" non ce ne siano proprio (salvo quello ereditato da Object che per i motivi che sappiamo non funziona in questi casi).

misterx
19-02-2004, 20:32
e bravo

e io non riesco ada abbandonare il concetto che equals è un metodo che va implementato ogni volta e non una funzione superautomatica di java :D

mi ero fissato che passando ad equals due indirizzi ci pensasse lui a scandire l'intera scheda, quella della classe precedente da me postata; invece va sbriciolata ed analizzata elemento per elemento

me ne dimentico sempre:muro:

misterx
20-02-2004, 08:02
leggo che in java l'unico modo per scambiare dati tra metodi è per valore e non per riferimento ?

mi viene in mente il compareTo dove gli viene passato un indirizzo=riferimento

ma vi sono anche altri casi analoghi dove ad un metodo viene passato un riferimento; che significa in java tutto ciò ?

che viene alterato all'interno di un metodo una copia e non l'originale ?:confused:

PGI
20-02-2004, 11:49
All'interno del metodo è alterata una copia se il passaggio è per valore (capita solo con i primitivi).

Se il passaggio è per riferimento viene creata una copia del riferimento: chiamare un metodo o modificare un campo del riferimento-copia genera un mutamento corrispondente sull'oggetto in memoria, osservabile anche attraverso il riferimento originale. Riassegnare il riferimento copia, al contrario, non comporta un corrispondente riassegnamento dell'originale, poichè l'oggetto puntato originariamente rimane dov'era.

A questo punto si può giustificare quello che hai letto: affinchè due metodi possano interagire con lo stesso valore si rende necessario incapsulare il valore (di un primitivo o di un riferimento) all'interno di un oggetto, il cui puntatore sarà passato tra i metodi.

recoil
20-02-2004, 13:02
riassumento puoi dire che in Java i parametri sono passati sempre per valore.
se pero' consideri che l'istanza di un oggetto rappresenta il puntatore all'area di memoria allora puoi concludere che il passaggio di parametri (tranne che nel caso di tipi primitivi) ha lo stesso effetto di un passaggio per riferimento

misterx
20-02-2004, 13:22
Originariamente inviato da recoil
riassumento puoi dire che in Java i parametri sono passati sempre per valore.
se pero' consideri che l'istanza di un oggetto rappresenta il puntatore all'area di memoria allora puoi concludere che il passaggio di parametri (tranne che nel caso di tipi primitivi) ha lo stesso effetto di un passaggio per riferimento


azz, sono andato in confusione

- il metodo main passa un valore ad altro metodo attraverso i suoi parametri

- i parametri di un metodo il mio libro dice che sono locali, ed è vero perchè dall'esterno sono invisibili

- il metodo ricevente agendo in un'area di memoria protetta, modifica il valore pervenutogli dal main

- quando il metodo ricevente lo ritorna al metodo main, è il metodo main stesso che lo sostituisce col nuovo

se è così è, boh, mi sembra un ottimo modo per proteggersi in quanto non possono due metodi alterare allo stesso tempo il medesimo valore

cmq, non so se ho capito

PGI
20-02-2004, 14:08
Originariamente inviato da recoil
riassumento puoi dire che in Java i parametri sono passati sempre per valore.



Riassumendo io direi il contrario, significa che sono stato veramente molto chiaro, mi devo fare i complimenti da solo :D.

misterx
20-02-2004, 14:14
Originariamente inviato da PGI
Riassumendo io direi il contrario, significa che sono stato veramente molto chiaro, mi devo fare i complimenti da solo :D.


non hai risposto alle mie perplessità :D

PGI
20-02-2004, 14:27
Mah, qui si comincia a parlare di parametri, valori, riferimenti, istanze di oggetti e metodi che restituiscono cose, la creatività è magnifica ma bisognerebbe quantomeno chiarire un attimo per ogni termine cosa si intende. Dovremmo farlo ogni volta che scriviamo un post, tipo "il metodo "a" passa il riferimento (puntatore ad un'istanza di classe in memoria) al metodo "b", b riceve una copia del riferimento (puntatore alla stessa istanza di classe del riferimento passato da a), maneggia questa copia e poi restituisce il controllo al metodo chiamante (return). Se specificato restituisce anche un tipo (reference o primitivo)".

misterx, tu mi scrivi "il metodo chiamante lo ritorna al main" non era il main il chiamante? E che ritorna? Al metodo ricevente è arrivato un valore? Perchè? Troppe domande per i miei due neuroni! :D

misterx
20-02-2004, 14:30
Originariamente inviato da PGI
Mah, qui si comincia a parlare di parametri, valori, riferimenti, istanze di oggetti e metodi che restituiscono cose, la creatività è magnifica ma bisognerebbe quantomeno chiarire un attimo per ogni termine cosa si intende. Dovremmo farlo ogni volta che scriviamo un post, tipo "il metodo "a" passa il riferimento (puntatore ad un'istanza di classe in memoria) al metodo "b", b riceve una copia del riferimento (puntatore alla stessa istanza di classe del riferimento passato da a), maneggia questa copia e poi restituisce il controllo al metodo chiamante (return). Se specificato restituisce anche un tipo (reference o primitivo)".

misterx, tu mi scrivi "il metodo chiamante lo ritorna al main" non era il main il chiamante? E che ritorna? Al metodo ricevente è arrivato un valore? Perchè? Troppe domande per i miei due neuroni! :D


e vabbè, un piccolo errore dovuto alla........ ed alla ...... ed a....:D

ho corretto ;)

PGI
20-02-2004, 14:52
Non è una questione di semantica, non mi permetterei mai di segnalare ironicamente un errore di battitura, proprio io che ho lo dita dotate di volontà propria (a malapena evito di ribattere le stesse cose dieci volte)

Originariamente inviato da misterx
azz, sono andato in confusione

- il metodo main passa un valore ad altro metodo attraverso i suoi parametri


Quindi il main sta chiamando un altro metodo che accetta come parametro un primitivo (boolean o numerico). Questo è il senso di quella frase, per come funziona Java, ma, scommetto un decino, non è quello che volevi dire (vero o no?)


- i parametri di un metodo il mio libro dice che sono locali, ed è vero perchè dall'esterno sono invisibili


Gosling conferma e noi, con due fonti (il tuo libro più il mio), ci fidiamo. E' così.


- il metodo ricevente agendo in un'area di memoria protetta, modifica il valore pervenutogli dal main


Il metodo ha in mano qualcosa di diverso da quello che gli è stato passato: una variabile di tipo primitivo che ha lo stesso valore di quella che è stata usata per chiamare il metodo, ma che punta ad una locazione di memoria diversa. Non è una questione di ricamo, la faccenda è molto diversa.

Dopo scrivo un paio di linee di codice per spiegarmi con più chiarezza.


- quando il metodo ricevente lo ritorna al metodo main, è il metodo main stesso che lo sostituisce col nuovo


Qui pare che la cosa sia automatica ma in realtà un metodo, sappiamo, non restituisce nulla se non è predisposto per farlo.


se è così è, boh, mi sembra un ottimo modo per proteggersi in quanto non possono due metodi alterare allo stesso tempo il medesimo valore


Ogni metodo ha un "lucchetto" attivabile proprio per evitare che due metodi agiscano insieme su uno stesso valore (dove valore è quello che sta in memoria, cioè un valore-oggetto o un valore-numerico o un valore-boolean). Qui pare che sia una bizzarria inventata da un matto per appensantire un po' le cose, non è cos', i metodi possono concretamente alterare allo stesso tempo lo stesso valore, se vengono chiamati "insieme" possono capitare guai sulla coerenza dei dati.

PGI
20-02-2004, 15:23
Procediamo un pezzo per volta.


Questo è il nostro "dato".


public class Contatto {
public String nome = null;
public String cognome = null;

public Contatto(String nome, String cognome) {
this.nome = nome;
this.cognome = cognome;
}

public String toString() {
return super.hashCode()+ " "+ nome + " " +cognome;
}
}


1) Passaggio per riferimento (ogni volta che il parametro di un metodo è di tipo "reference" -> "riferimento")


public class Esperimento {
/** main */
public static void main(String... args) {
new Esperimento().eseguiEsperimento();
}


public void eseguiEsperimento() {
Contatto marioRossi = new Contatto("Mario", "Rossi");
Contatto giulioBianchi = new Contatto("Giulio", "Bianchi");

System.out.println("valore originale puntato");
System.out.println(marioRossi);
System.out.println(giulioBianchi);

System.out.println("passaggio per riferimento");
modificaPuntamento(marioRossi);
modificaPuntamento(giulioBianchi);

System.out.println("cosa e' cambiato ?");
System.out.println(marioRossi);
System.out.println(giulioBianchi);
}

public void modificaPuntamento(Contatto riferimento) {
riferimento = new Contatto("Beppe", "Neri");
}
}


L'output è:


valore originale puntato
17523401 Mario Rossi
8567361 Giulio Bianchi
passaggio per riferimento
cosa e' cambiato ?
17523401 Mario Rossi
8567361 Giulio Bianchi


Non è cambiato un bel cavolo.

Perchè? Due motivi:

1) passando un tipo-reference non passo il valore a cui il reference punta: se così fosse, infatti, creando nel metodo "modificaPuntamento" un nuovo oggetto ed assegnandolo al parametro, la variabile-reference originale (marioRossi) dovrebbe ritrovarsi puntata nella stessa locazione di memoria, la quale avrebbe tuttavia un valore diverso.

2) passando un tipo reference il metodo ottiene una copia del reference, cioè un nuovo tipo reference che punta alla stessa locazione di memoria. Assegnando a questa copia un nuovo valore, non viene chiaramente intaccato il valore originale di marioRossi. Se il reference ottenuto dal metodo modificaPuntamento fosse lo stesso reference "di partenza", o un puntatore al reference originale (puntatore ad un puntatore, che in Java non esiste), modificando "riferimento" dovrei ottenere un cambiamento riflesso in "marioRossi", che invece non c'è.

PGI
20-02-2004, 15:41
Proviamo con i primitivi?


public class Esperimento {
/** main */
public static void main(String... args) {
new Esperimento().eseguiEsperimento();
}


public void eseguiEsperimento() {
int intero = 10;
System.out.println("prima del passaggio");
System.out.println(intero);
System.out.println("dopo il passaggio");
passaggioPerValore(intero);
System.out.println(intero);
}

public void passaggioPerValore(int primitivo) {
primitivo = 20;
}
}


prima del passaggio
10
dopo il passaggio
10

Cosa cambia? Un...un...cavolo.

Ed ecco la prima norma di coerenza che si ritrova in Java: il passaggio per valore (primitivo) e riferimento (reference) garantisce che il riassegnamento operato all'interno di un metodo produca lo stesso effetto (indifferenza rispetto al contenuto della variabile presente nel metodo chiamante).

Abbiamo visto che se i reference fossere passati per valore questo non succederebbe: e questo curiosamente non tutti lo scrivono (vedi Using Java 1.1, che parla di ambiguità, trascurando del tutto la parte del riassegnamento)

PGI
20-02-2004, 16:06
Adesso vediamo come produrre attraverso un metodo una modifica di un oggetto, passato per riferimento.


public class Esperimento {
/** main */
public static void main(String... args) {
new Esperimento().eseguiEsperimento();
}


public void eseguiEsperimento() {
Contatto marioRossi = new Contatto("Mario", "Rossi");
System.out.println("Prima delle modifiche");
System.out.println(marioRossi);
System.out.println("Dopo le modifiche");
modificaContenuto(marioRossi);
System.out.println();
System.out.println("Un modo per modificare tutto");
System.out.println("Prima delle modifiche");
System.out.println(marioRossi);
System.out.println("Dopo le modifiche");
marioRossi = modificaContatto(marioRossi);
System.out.println(marioRossi);
}

public void modificaContenuto(Contatto contatto) {
contatto.nome = "Beppe";
contatto.cognome = "Neri";
}

public Contatto modificaContatto(Contatto contatto) {
contatto = new Contatto(contatto.nome, "Calvi");
return contatto;
}
}


Prima delle modifiche
17523401 Mario Rossi
Dopo le modifiche

Un modo per modificare tutto
Prima delle modifiche
17523401 Beppe Neri
Dopo le modifiche
8567361 Beppe Calvi

modificaContenuto non restituisce nulla, ma cambia due campi all'interno dell'oggetto contatto: il cambiamento si riflette sul reference originale perchè la copia opera sulla stessa parte di memoria (dal codice hash si capisce che è lo stesso oggetto a cui puntava l'originale)

modificaContatto restituisce un diverso oggetto (si vede perchè è diverso il codice hash) il cui contenuto è in parte uguale a quello a cui puntava il riferimento. Il principio è lo stesso di quello dell'interfaccia "clone": questo approccio è però dispersivo, perchè "butta via" l'oggetto originale in memoria (dereferenziandolo), ne crea uno nuovo e lo "assegna" al riferimento originale (è un po' come funziona il "clone", nell'interfaccia Cloneable)

cn73
20-02-2004, 17:46
Bella lezione PGI ;)

Vediamo se i tuoi alunni hanno capito:
Senza eseguire mi dite l'output di questo programmino?


class Referenza {

static int a;
static java.util.Vector vector;

public static void main(String[] arg) {

a=1;
System.out.println("a= : " + a);
modificaInt(a);
System.out.println("a= : " + a);

vector=new java.util.Vector();
System.out.println("size : " +vector.size());
modificaVector(vector);
System.out.println("size : " +vector.size());
modificaVectorPointer(vector);
System.out.println("size : " +vector.size());

}

static void modificaInt(int a){
a--;
}

static void modificaVector(java.util.Vector v){
v.addElement(new Object());
}

static void modificaVectorPointer(java.util.Vector v){
v=new java.util.Vector();
v.addElement(new Object());
v.addElement(new Object());
}

}

misterx
20-02-2004, 18:17
vediamo se ho capito e tranquillo che non baro; il compilatore è OFF :D


class Referenza {

static int a;
static java.util.Vector vector;

public static void main(String[] arg) {

a=1;
System.out.println("a= : " + a); a = 1
modificaInt(a);
System.out.println("a= : " + a); a = 1

vector=new java.util.Vector();
System.out.println("size : " +vector.size()); 1 // qui non so se new Vector aggiunge qualcosa al size se si, vale 1 altrimenti 0; di conseguenza quelli sotto valgono 1 tutti e due
modificaVector(vector);
System.out.println("size : " +vector.size()); 2
modificaVectorPointer(vector);
System.out.println("size : " +vector.size()); 2

}

static void modificaInt(int a){
a--;
}

static void modificaVector(java.util.Vector v){
v.addElement(new Object());
}

static void modificaVectorPointer(java.util.Vector v){
v=new java.util.Vector();
v.addElement(new Object());
v.addElement(new Object());
}

} [/QUOTE]

cn73
20-02-2004, 18:51
La seconda che hai detto...new Vector crea un puntatore ad un oggetto di tipo Vector vuoto...perciò size è 0... per il resto ci siamo ;)

misterx
20-02-2004, 18:59
allora è giusto ?

ho pensato che a non venisse minimamente alterata in quanto quella nel metodo è una copia

nel secondo caso, il primo metodo condivide un puntatore, il secondo metodo ne inizializza uno per i fatti suoi


cmq, cn, bell'esempio ;)

recoil
21-02-2004, 18:45
Originariamente inviato da PGI
Riassumendo io direi il contrario, significa che sono stato veramente molto chiaro, mi devo fare i complimenti da solo :D.

secondo te sono passati per riferimento? io dico di no
i tipi primitivi vengono sicuramente passati per valore (provare per credere) e anche gli oggetti sono passati "per valore".
come ho già detto quel valore rappresenta un indirizzo di memoria, ma viene passato per valore. se ci fosse un vero passaggio per riferimento avremmo una specie di puntatore di puntatori

PGI
21-02-2004, 20:13
Originariamente inviato da recoil
secondo te sono passati per riferimento? io dico di no
i tipi primitivi vengono sicuramente passati per valore (provare per credere) e anche gli oggetti sono passati "per valore".
come ho già detto quel valore rappresenta un indirizzo di memoria, ma viene passato per valore. se ci fosse un vero passaggio per riferimento avremmo una specie di puntatore di puntatori

D'accordo sui primitivi, non ci sono puntatori a primitivi, non possono che essere passati per valore.

Sugli oggetti resto dell'idea che sia un passaggio per riferimento, il metodo non ottiene una copia del valore a cui punta il riferimento (cioè l'oggetto), ma un riferimento che punta allo stesso oggetto.


class Esperimento {

public static void main(String[] arg) {
new Esperimento();
}

class Dato {
String stato = "vuoto";
}

public Esperimento() {
Dato oggetto = new Dato();
System.out.println("oggetto in Esperimento()");
System.out.println(oggetto.stato);
metodoRiferimento(oggetto);
System.out.println("oggetto in Esperimento()");
System.out.println(oggetto.stato);
}

void metodoRiferimento(Dato dato) {
dato.stato = "pieno";
}
}


oggetto in Esperimento()
vuoto
oggetto in Esperimento()
pieno

Se fosse un passaggio per valore, perchè "oggetto" rifletterebbe le modifiche apportate da "metodoRiferimento"?

misterx
21-02-2004, 20:27
PGI, anch'io la pensavo come te ma ho dovuto cambiare idea

PGI
21-02-2004, 20:54
Sono contento, tuttavia io penso che qui non sia questione di cambiare idea ma di capire di che stiamo parlando.

Quando una variabile è passata per valore, il codice del metodo/funzione non può modificarne il valore. Quando una variabile è passata per riferimento, il codice del metodo/funzione può modificarne il valore.

Parliamo di "passaggio per valore e per riferimento"? Benissimo, in Java tutti i primitivi sono passati per valore e tutti gli oggetti per riferimento. Non c'è la soluzione "B".

In C l'alternativa c'è. Se usi un puntatore, passi l'argomento per riferimento, se usi la variabile "passi per valore".

misterx
21-02-2004, 21:31
è sempre per valore in quanto il chiamante fa una copia dell'indirizzo (che è un valore memorizzato nella variabile puntatrice) che riceve

qui è spiegato abbastanza bene

http://www.webaiuto.it/faq/pagine/1454.php

cmq, la differenza è sottile

PGI
21-02-2004, 22:01
Non ho capito una parola di quello che è scritto in quelle faq.

Che ognuno conservi la propria idea, e passiamo avanti!

PGI
21-02-2004, 23:17
MA DAI! MA PENSA!
Ma avevate ragione!
MA DAI!.
Java passa tutto per valore!
Ma guarda un po' cosa non si va a scoprire! :eek:

misterx
22-02-2004, 10:12
Originariamente inviato da PGI
MA DAI! MA PENSA!
Ma avevate ragione!
MA DAI!.
Java passa tutto per valore!
Ma guarda un po' cosa non si va a scoprire! :eek:



non ti lamentare, io sono andato avanti anni pensando che il C...... vabbè, quello che abbiamo detto sopra


a mio avviso è colpa della terminologia non sempre azzeccata

PGI
22-02-2004, 15:25
A me sta cosa del passaggio per valore però "non va proprio giù".

Complica notevolmente le cose dover pensare a Java come ad un "pass-by-value".

Seduta stante, propongo di pigliare la "spiegazione" di James Gosling ("java è un pass-by-value, perchè non passa oggetti per riferimento ma riferimenti ad oggetti per valore") e farne un tipo a sè (cosa che Giovanni Papero non fa).

{ "pass-by-name" (Pascal, Algol)? }
"pass-by-reference"

"pass-by-value" -> Java (primitive)
"pass-reference-by-value" -> Java (reference)

dove il "pass-reference-by-value" si comporta così:

tutte le operazioni che mutano il valore del reference restano isolate all'ambito (scope) del metodo invocato.

tutte le operazioni che mutano il valore dell'oggetto puntato dal reference si trasmettono all'ambito (scope) del metodo invocante.

E' più chiaro o più oscuro?

Anche perchè, che cavolo se ne fa uno del passaggio per valore di un riferimento, posto che non ci sono operazioni possibili sul valore di un riferimento diverse dal "ri-assegnamento"?

Al solito, si accettano commenti, frecciate e sberleffi.

theClimber
22-02-2004, 15:43
Originariamente inviato da PGI
Anche perchè, che cavolo se ne fa uno del passaggio per valore di un riferimento, posto che non ci sono operazioni possibili sul valore di un riferimento diverse dal "ri-assegnamento"?


beh, puoi "utilizzare" il riferimento per accedere all'oggetto referenziato, non mi sembra poco ! ;)

Alla fine tutto dipende dal meccanismo di invocazione dei metodi attraverso lo stack (quindi da meccanismi di basso livello) ... Dire quindi che tutto e' passato per valore e' quindi corretto, ma in un certo senso crea confusione in quanto il riferimento e' utilizzato per accedere ad oggetti manipolabili.

Alla fine la spiegazione che avevi gia' dato e' Ok, in quanto le reference agli oggetti sono si passate per valore (e quindi non modificabili), ma di conseguenza gli oggetti sono acceduti "per riferimento" (Un oggetto passato per valore cosa sarebbe?? un clone dell'oggetto infilato nello stack di invocazione?? a questo punto come potrei avere delle refernce allo stack? :confused: ;)).

PGI
22-02-2004, 16:37
Originariamente inviato da theClimber
beh, puoi "utilizzare" il riferimento per accedere all'oggetto referenziato, non mi sembra poco

si, questa però non è un'operazione sul valore della variabile passata.

La faccenda è poco "lineare".

Con i primitivi è tutto perfetto: passo il valore, il metodo si trova una copia del primitivo nel suo pezzetto di memoria, tutto quello che fa con quel valore non "contamina" il resto del codice.

Con i reference no. Ad esempio posso "pasticciare" con l'oggetto puntato [e qui sembra un passaggio per riferimento dell'oggetto](che tecnicamente non è il valore del reference ma in buona sostanza l'unico scopo per cui esistono i reference è quello di puntare al valore di un oggetto, forse è questo che trae in inganno, si è portati a pensare che il valore del reference sia l'oggetto), ma non posso fare uno "swap" del contenuto di due reference [e qui siamo in un passaggio per valore dell'oggetto]

Qui Java mi sembra tenga il piede in due staffe, male in entrambe (dal punto di vista dell'uso, che poi sia un "pass-by-value" in senso tecnico ha poca importanza, proprio perchè il valore di un reference non è un dato significativo).

A tempo perso, è una questione su cui rimuginare un po'.

theClimber
22-02-2004, 17:11
Originariamente inviato da PGI
Qui Java mi sembra tenga il piede in due staffe, male in entrambe (dal punto di vista dell'uso, che poi sia un "pass-by-value" in senso tecnico ha poca importanza, proprio perchè il valore di un reference non è un dato significativo).


Sono d'accordo al 100%.

Agginungo solo un po del mio rimuginare sulla questione:

Io la faccenda la vedo come un astrazione costruita sopra (o piu' precisamente per mezzo) l'implementazione del passaggio della reference nello stack delle invocazioni a metodi della JVM (La quale alla fine e' un astrazione sul codice macchina eseguito.... alla fine si deve arrivare sempre lì :mc: ).

Provo a spiegarmi con 2 esempi di astrazioni refence/value:

se passo un int ed e' la primary key di un record di un database, ci potrei pasticciare sopra alla grande sul Db. Ma comunque non potrei cambiare il valore del primitivo al chiamante.
(Questa e' una mia implementazione custom del call by reference usando il call by value)
cosa succede con una stringa? E' un oggetto, pero' immutabile e quindi indipendentemente dal fatto che ho la refence dell'oggetto, non lo posso cambiare comunque. (In pratica ho un call by value anche con una reference. Beh, + o - ;) in ogni caso e' protetto da modifica )


Personalment trovo che sia una cosa equivalente parlare di passaggio per riferimento degli oggetti o del passaggio per valore della reference all'oggetto, una volta che il meccanismo di astrazione per accedere all'oggetto puntato sia definito (cosa che in java e' inclusa nel linguaggio, mentre nel primo esempio che ho fatto sopra e' un impl. totalmente custom).

Ciao

PS:
sono queste cose (come dicevi Java sembra tenere male il piede in 2 scarpe) che ogni tanto mi fanno un po odiare java e preferire linguaggi come Ruby e Smalltalk, dove ci sono solo oggetti, quindi tutto e' + uniforme, elegante e ci sono meno sorprese e quindi meno errori :D

misterx
22-02-2004, 20:22
mi viene da pensare che un vero passaggio per riferimento mi permetterebbe quanto segue:

il metodoA chiama il metodoB passando lui un riferimento

nel tragitto, il metodoA si diverte a modificare la posizione (indirizzo) dell'oggetto quindi, il metodoB si troverebbe spiazzato e ad operare su una zona di memoria non più valida, dove cacchio è l'oggetto?

ma........ma metodoB avendo ereditato il riferimento dal metodoA è in grado di seguirne gli spostamenti: va che ti curo :D

mah.........

avevo voglia di sparare cazzate :D

recoil
22-02-2004, 20:43
Originariamente inviato da misterx
il metodoA chiama il metodoB passando lui un riferimento

nel tragitto, il metodoA si diverte a modificare la posizione (indirizzo) dell'oggetto quindi, il metodoB si troverebbe spiazzato e ad operare su una zona di memoria non più valida, dove cacchio è l'oggetto?

ma........ma metodoB avendo ereditato il riferimento dal metodoA è in grado di seguirne gli spostamenti: va che ti curo :D

una teoria interessante. in questo caso sarebbe la VM a gestire la memoria associando a questo riferimento (una sorta di ID) la posizione corretta, ovvero la più aggiornata in base agli spostamenti

theClimber
22-02-2004, 20:51
In pratica verrebbe:

passato per valore il riferimento al riferimento all'oggetto, oppure
passato per riferimento il riferimento all'oggetto


aarrghh :muro: :D:D

misterx
27-02-2004, 09:08
il seguente codice come è giusto non compila ma sarebbe stato bello se il messaggio di errore fosse stato:

I mammiferi non sbuffano aria

in luogo di:

Animali.java [7:1] cannot resolve symbol
symbol : method SbuffaAria ()
location: class Mammiferi
System.out.println( m.SbuffaAria() );
^
1 error
Errors compiling Animali.





public class TestAnimali {

public static void main(String[] args) {

Mammiferi m = new Balena();

System.out.println( m.SbuffaAria() );
}
}


class Mammiferi {

public String sono(){
return "animali che possono vivere sia sulla terra ferma che in acqua";
}
}

class Balena extends Mammiferi {

public String SbuffaAria(){
return "la balena sbuffa aria";
}

}

PGI
28-02-2004, 11:51
Beh, si può fargli dire che i mammiferi che non sono balene non sbuffano aria, però capisco il punto su cui sei andato a parare.

Esistono, forse, dei casi in cui sarebbe "comodo" avere un'ereditarietà bi-direzionale (con relativo polimorfismo), anche se a questo punto occorrerebbe trovare al fenomeno un altro nome, i figli comunemente trasmettono ai padri conti da pagare, qualche denuncia penale, due o tre manifestazioni d'affetto, mai il proprio patrimonio genetico.

misterx
28-02-2004, 13:44
cmq, java è più bello da studiare che usare ;)

PGI
28-02-2004, 16:36
Beh, insomma, è piuttosto carino anche da usare via, soprattutto per via delle sue librerie "standard". Trovami un altra "lingua" che abbia dalla sua una documentazione delle librerie paragonabile a quella di Java

misterx
28-02-2004, 17:19
eheh, è arrivato il mio momento di fare un pò il teorico; ho sempre programmato ma seguendo molto il mio intuito, fortunatamente non mi ha mai abbandonato :)


stavo leggendo qui: ---> http://www.developer.com/java/other/article.php/991451


hai di meglio ?

azz, continuo a leggere cose che so già ma per le quali penso sempre di avere dei dubbi :muro:

cmq, polimorfismo è un sacco di cose, in quanto concetto legato ad un sacco di altre cose :)

posso dire che è una conseguenza di alcuni comportamenti degli oggetti ?

PGI
28-02-2004, 17:52
> posso dire che è una conseguenza di alcuni comportamenti degli oggetti

Al solito, puoi dire tutto quello che ti aiuta a comprendere meglio il linguaggio (basta non spacciarlo per verità assoluta)

Io trovo più "corretto" pensare al polimorfismo come ad una caratteristica che permette agli oggetti di assumere la forma più utile ai fini dei programmi. Se cominciama a scavare più a fondo, beh, si può dubitare di alcune cose.

Ad esempio, il "sovraccaricamento" è polimorfismo?

In Java un metodo è identificato dal nome e dai suoi argomenti, stesso nome, argomenti diversi, metodi diversi.

Beh, mi dirai, ma anche le classi parent-child sono pur sempre delle classi diverse.

Sì, però il figlio eredita le caratteristiche del padre, il che ne fa "concettualmente" una specie dello stesso genere. Il riferimento di tipo padre è polimorfico perchè può eventualmente "puntare" a qualcosa che "è almeno" un padre.

Per i metodi come la mettiamo? "faiqualcosa(int)" che cosa "lascia" a "faiqualcosa(String)"? Il nome? e che te ne fai?

Sei costretto ad usare la riflessione per avere il polimorfismo dei metodi, mi sembra una cosa molto "di nicchia".

Non so, sono indeciso.

misterx
28-02-2004, 18:08
beh, se guardi al link da me postato ci trovi qualche conferma di quanto ho detto

verità assoluta ????
chi ha mai detto che pigiandi io i tasti della mia testiera scriva verità assolute ??? :D:D:D

me la vendo facile :D senza overload e overriding penso non esisterebbe il polimorfismo(terzo pilastro del OOP)

a me la storia degli oggetti polimorfici non va giù in quanto sembrerebbe che tali oggetti possono avere più forme in funzione di una qualcosa, come se si adeguassero

se penso ad una classe astratta come ad un oggetto allora tutto fila via come il vento

occhio al ragionamento che non è corretto :D serve solo per capire

class animale......

class giraffa extends animale......

class.......

class.......

animale m = new giraffa();
m.toString(); "verso della giraffa"

animale m = new leone();
m.toString(); "verso della leone"

animale m = new zebra();
m.toString(); "verso della zebra"

praticamente un animale(oggetto) generico che si adegua in funzione di....polimorfismo ?


tu parlavi anche nelle tue ultime battute della scelta da parte del compilatore del metodo più giusto da eseguire

miovalore(int valore)

miovalore(long valore)

miovalore(double valore)

so solo che è in funzione di quello che offre il minor numero di promozioni

PGI
28-02-2004, 18:26
> beh, se guardi al link da me postato ci trovi qualche conferma di quanto ho detto

:D Nel link vedo una persona che parla del polimorfismo, fosse San Gennaro potremmo chiudere la questione, non vedo l'aureola, discutiamone.

Occhio comunque, che anche nella pagina da te linkata, si dice

"From a practical programming viewpoint, polymorphism manifests itself...". Non parla del polimorfismo, parla di come sia possibile osservarne gli effetti attraverso l'overloading ecc...

Non confondiamo il modo in cui una cosa si manifesta con la cosa manifestata.

> so solo che è in funzione di quello che offre il minor numero di promozioni

e no dai, questa no! :D

Non è che la jvm si metta a scegliere il metodo che le sembra più performante.

Usa il metodo che le dici di usare.

Se gli passi un int usa il metodo con l'int ecc.

misterx
28-02-2004, 18:39
aspe, nel caso di overloading è veramente il compilatore a scegliere il metodo da usare in funzione di quello che offre il minor numero di promozioni

chettedevodì, l'hanno venduta anche a me così e non ho ancora smembrato la JVM per sincerarmene: cmq, penso sia vero

> Nel link vedo una persona che parla del polimorfismo, fosse San Gennaro potremmo chiudere la questione, non vedo l'aureola, discutiamone.

infatti ti avevo chiesto un link ma hai fatto scena muta :D

per ogni aggiornamento sono sempre nei dintorni :)

cmq, polimorfismo significa un sacco di cose, non solo una: la accendiamo ?? :D:D:D


Il termina polimorfismo indica la possibilità di definire all'interno di più classi metodi e proprietà con lo stesso nome, in modo che, ad esempio, una classe derivata possa ridefinire un metodo della classe base con lo stesso nome.

PGI
28-02-2004, 19:06
Originariamente inviato da misterx
aspe, nel caso di overloading è veramente il compilatore a scegliere il metodo da usare in funzione di quello che offre il minor numero di promozioni


E no.

Se noi dicessimo così allora il codice che segue:


public class Prova {
public static void main(String[] a) {
char c = 'd';
new Prova().conta(c);
}

public void conta(byte valore) {
System.out.println("byte");
}

public void conta(short valore) {
System.out.println(valore);
}

public void conta(int valore) {
System.out.println("int");
}

public void conta(long valore) {
System.out.println("long");
}

public void conta(float valore) {
System.out.println("float");
}

public void conta(double valore) {
System.out.println("double");
}
}


dovrebbe dare "byte". Perchè invece salta fuori int?

Perchè non fa una scelta guardando al "numero di promozioni" (che è uno solo, un char passa "direttamente" a long, senza diventare un byte, poi uno short e infine un int. Il "come", dipende dalla specifica implementazione della jvm, ma la regola non è "manipolabile").

Molto meno "volitivamente", tutto quello che è "sotto" l'int viene promosso a "int" e sopra l'int c'è solo il long. Il float viene eventualmente promosso nell'unica possibilità che c'è, un double.

Qua se cominciamo a parlare di macchine virtuali che scelgono seminiamo il terrore.

Se scrivessi due metodi che richiedono uno un double e l'altro un long e poi gli passo un char che fa la jvm? Anghingò e poi me ne rifila uno a caso? :D

misterx
28-02-2004, 19:46
sbagli, ed è il tuo esempio che ti porta fuori strada :D

il compiltore non saprebbe scegliere solo in casi tipo questo:

calcola(int a , double b)

calcola(double a , int b)


se gli passi due interi

calcola(10,10) errore in compilazione

PGI
29-02-2004, 00:06
Adesso ho capito cosa intendevi (ci ho messo una vita, ma quando si nasce volpe!). E mi pareva strano che pensassi al "numero di promozioni" come al numero di volte che un primitivo avrebbe dovuto essere "gonfiato" per corrispondere all'argomento.

La regola sulla scelta dei metodi da parte del compilatore, però, non è quella. :eek:

misterx
29-02-2004, 10:48
ok, un pò di fatica l'ho fatta pure io stavolta :D


A Anna;
B Barbara;
C Claudia;

--> Anna.assegna(2); (ok)
--> Anna.assegna(2.0); (errore!)


--> Barbara.assegna(2);

qui il compilatore può sciegliere tra:
assegna(int x) --> metodo di B
assegna(double x) --> metodo di B
assegna(long x) --> metodo di A

+--------------------------+
| A |
+--------------------------+
| -a: long |
+--------------------------+
| +assegna(x:long): void |
| +toString(): String |
+--------------------------+
/\
+--------------------------+
| B |
+--------------------------+
| -b1: int |
| -b2: double |
+--------------------------+
| +assegna(x:int): void |
| +assegna(x:double): void |
| +toString(): String |
+--------------------------+
/\
+--------------------------+
| C |
+--------------------------+
| -c1: int |
| -c2: double |
+--------------------------+
| +assegna(x:int): void |
| +assegna(x:double): void |
| +toString(): String |
+--------------------------+

PGI
29-02-2004, 14:12
Io ci avrei messo cent'anni a scrivere così bello ordinato :eek:

Però non ho capito bene qual'è la regola espressa (e alla fine è quella che vogliamo). Mi è chiaro che per via dell'ereditarietà e dei metodi "propri" alla fine il compilatore "potrebbe" sceglierne uno dei 3 di B, ma qual'è quello che sceglie e, sopratutto, perchè?

E quando non compila per "ambiguità", perchè lo fa? E quando lo fa?

E infine, chi siamo, da dove veniamo e dove andiamo? :D

misterx
06-03-2004, 18:42
Originariamente inviato da PGI
Io ci avrei messo cent'anni a scrivere così bello ordinato :eek:

Però non ho capito bene qual'è la regola espressa (e alla fine è quella che vogliamo). Mi è chiaro che per via dell'ereditarietà e dei metodi "propri" alla fine il compilatore "potrebbe" sceglierne uno dei 3 di B, ma qual'è quello che sceglie e, sopratutto, perchè?

E quando non compila per "ambiguità", perchè lo fa? E quando lo fa?

E infine, chi siamo, da dove veniamo e dove andiamo? :D


non dire cavolate PGI :)

cmq, sono passato ad altro, JAVA per un pò lo lasciamo dormire e tra qualche anno ripassiamo :D

PGI
06-03-2004, 20:29
Senza qualche cavolata ogni tanto che campiamo a fare! :D

In bocca al lupo per la nuova avventura, se mantieni lo spirito curioso sono più che sicuro che non avrai problemi a padroneggiare quello che deciderai di studiare :).

C#iao.