Newsgroup: it.comp.java
Titolo: [JustForFun] Prova d'Esame

Ciao,
se qualcuno si fosse trovato a leggere un paio di miei thread, di 
qualche giorno fa, avrà capito che dovevo fare un esamuccio su java. 
Beh, volevo mostrarvi un paio di domande che mi sono sembrate 
divertenti, provate a rispondere senza compilare!
E motivate le risposte! :P
// DOMANDA #1
//
// Qual è l'output del seguente pezzo di codice?
// (questa era impossibile, e l'ho sbagliata! :( )
class A {
     private int f() { return 0; }
     public int g() { return 3; }
}
class B extends A {
     private int f() { return 1; }
     public int g() { return f(); }
}
class C extends B {
     public int f() { return 2; }
}
public class Main {
     public static void main(String[] args) {
         A ref1 = new C();
         B ref2 = (B) ref1;
         System.out.println(ref2.g());
     }
}
// DOMANDA #2
// E' possibile creare array di lunghezza zero?
//
// (sembra facile, ma non m'ero mai posto il problema!)
// (comunque l'ho indovinata! :D)
A. Si, di qualunque tipo.
B. Si, ma solo di tipi primitivi.
C. Si, ma solo di riferimenti ad oggetti.
D. No, tranne per l’array ricevuto dal metodo main
contenente la lista degli argomenti della riga di
comando.
E. No, in nessun caso.
// DOMANDA #3
//
// Cosa c’`e di sbagliato nel codice seguente?
// (Questa pure l'ho sbagliata :( )
abstract class A implements I1, I2 {
    public void f() {}
    public void g() {}
}
interface I1 {
    int VAL_A = 1;
    int VAL_B = 2;
    void f();
    void g();
}
interface I2 {
    int VAL_B = 3;
    int VAL_C = 4;
    void g();
    void h();
}
A. La classe A non puo' implementare due interfacce.
B. La classe A non ha fornito l’implementazione del
metodo h() dell’interfaccia I2.
C. C’e' un conflitto delle dichiarazioni dei due metodi
g() nelle interfacce I1 e I2.
D. C’e' un conflitto delle dichiarazioni degli attributi
VAL_B nelle interfacce I1 e I2.
E. Non c’e' nulla di sbagliato.
Buon divertimento!
E non barate! Vi controllo! ;)

 metodo h() dell'interfaccia I2.
i metodi definiti in un iterfaccia devono sempre essere TUTTI
implementati dalla classe che implementa l'interfaccia.
Ciao Jack

 // Cosa c’`e di sbagliato nel codice seguente?
Confesso che questa mi ha dato da pensare. Andando per ragionamento ed esclusione:
A. La classe A non puo' implementare due interfacce.
questa e' palesemente sbagliata
B. La classe A non ha fornito l’implementazione del metodo h() dell’interfaccia I2.
e' abstract, non c'e' problema
La C e la D si richiamano a vicenda, o sono vere entrambe o sono false entrambe... non mi sono mai trovato in un caso del genere, ma probabilmente si fa come in C++ in cui esplicitamente fai riferimento a quale dei due sei interessato per risolvere l'ambiguita' (tipo I1.VAL_B oppure I2.VAL_B). Quindi le metterei entrambe false.
E. Non c’e' nulla di sbagliato.
Ecco mi rimane questa... quindi rispondo E.
Saluti
CarMas

 La C e la D si richiamano a vicenda, o sono vere entrambe o sono false entrambe... non mi sono mai trovato in un caso del genere, ma probabilmente si fa come in C++ in cui esplicitamente fai riferimento a quale dei due sei interessato per risolvere l'ambiguita' (tipo I1.VAL_B oppure I2.VAL_B). Quindi le metterei entrambe false.
Per la C e la D sono d'accordo con te, ma per la B...la teoria dice
che una classe che implementa un interfaccia deve implementarne tutti
i metodi, vero' pero' che A e' astratta.
Quindi secondo me anche se non lo implementa lo deve almeno
dichiarare, cosi:
abstract class A implements I1, I2 {
    public void f() {}
    public void g() {}
    public void h();  //astratto
}
ma poi come funziona?
class Pippo implements A{
    public void h(){}
}
oppure (credo questa)
class Pippo extends A{
    public void h(){}
}
Ciao Jack

 E. No, in nessun caso.
risposta: A

risposta: B

 }
Esattamente cosi'!
Saluti
CarMas

 // DOMANDA #3
*Jack*, *ab*: (ho risposto come voi all'esame) Risposta sbagliata! C'è 
abstract!
*CarMas*: sbagliato, però giusto il ragionamento per quanto riguarda la 
parola chiave abstract che permette alla classe che implementa di 
lasciare non implementato il metodo.
Questa anche è interessante per via di una cosuccia..
A dopo per le spiegazioni! ;)

 Ergo, se la dichiari abstract puoi omettere il metodo, sara' poi cura della classe concreta che la estende fornire una implementazione del metodo.
questo si.
Quello che pensavo era che, anche se non lo implemento, il metodo h()
lo devo ri-dichiarare perche' (mio ragionamento) chi ha accesso alla
classe A puo' non avere accesso all'interfaccia I1, e I2 (alla doc, al
source code,...), e quindi non sa che deve implementare h(). Cioe' chi
usa la classe A fondamentalmente puo' non essere a conoscenza che A
implementi l'interfaccia I1 e I2.
Ciao Jack

 domanda, ed anche perché la trovo molto interessante!
Mmh no, si vede che mi sono spiegato malissimo.
Qui e' chiaro che stampa 2, ref e' un oggetto di tipo B, quindi e'
chiaro che ha accesso al metodo B.x()
Nella domanda c'era:
  A ref1 = new C();
  B ref2 = (B) ref1;
quindi abbiamo ref1 che e' C, ref2 che e' B. Il cast serve a passare a
ref2 le cose di ref1 che B e C hanno in comune. Quindi non e' che
castri ref2.
poi si fa il println di ref2.g(). A questo punto il ragionamento per
scegliere lo g() giusto e' lo stesso che serve dopo per scegliere
l'f() giusto:
ref2 vede 2 g() quello di B (B.g()) e quello di A (A.g()). La VM
prende il g() piu' giovane (essendo A padre di B va da se che B.g() e'
piu' giovane di A.g()).
Quindi adesso che sappiamo che prende B.g() per fare il println
bisogna scegliere l'f() giusto.
Abbiamo 3 possibilita' A.f(), B.f() e C.f(). Seguando il ragionamento
di prima e' chiaro che usera' B.f() perche' essendo ref2 di tipo B ha
accesso solo a A.f() e B.f().
La pseudofregatura stava nel sapere cosa succede durante il cast. il
cast passa i valori (in comune tra due classi imparentate) non i
metodi.
Una cosa che mi chiedo e' come fare per far usare a ref2 A.g() (o
A.f(), e' uguale). Cioe' fare in modo che
System.out.println(ref2.g());
usi A.g() e non B.g() senza modificare la classe B.
Magari con un cast, una roba del genere?
System.out.println((A)ref2.g());
Ciao Jack

 ridefinizione di f quindi)
Errato. Stampa 2, ref2 non "prende tutte le cose che B e C hanno in 
comune", al massimo, rendeve visibili quelle definite in B. Binding 
dinamico, il tipo e' B ma l'oggetto e' C, quindi chiama la f di C che 
stampa 2.

 Qui e' chiaro che stampa 2
Prova, prova poi vedi cosa esce.
Max

 di prima e' chiaro che usera' B.f()
Che stampa 1. mi suona un po' contradditorio.

 wrote:

ho provato, infatti stampa 2.
-- 
Yoda of Borg am I! Assimilated shall you be! Futile resistance is, hmm?

 wrote:

No, stampa 1 (ho provato).
E cmq sarebbe completamente sbagliato concettualmente.
Faccio un esempio che magari rimane piu' semplice (eliminando g(), che
tanto e' inutile):
class Animale {
     public String f() { return "sono un animale"; }
}
class Orso extends Animale {
     public String f() { return "sono un orso"; }
}
class Panda extends Orso {
     public String f() { return "sono un panda"; }
}
public class Main {
     public static void main(String[] args) {
         Animale ref1 = new Panda();
         Orso ref2 = (Orso) ref1;
         System.out.println(ref2.f()); 
 
     }
}
questa cosa ritorna "sono un orso".
Ciao Jack


 *Jack*: Risposta Esatta, motivazione sbagliata.
ok, ho provato.
Tra l'altro anche CarMas ha risposto 1, ma gliel'hai data sbagliata.
Tutta la pappardella dei miei altri post e' giusta...parzialmente.
L'esempio con x() in effetti funziona come dico io, ma la domanda
d'esame era piu' subdola.
Il problema e' che B.f() e' private e non public. Se fosse public allora
la risposta sarebbe 2 (B.f() verrebbe ridefinito da C.f()). Pero' e'
private.
Questo fa si che B.g() veda solo B.f() e non C.f() perche' C.f(), anche
se si chiama uguale, NON e' l'override di B.f().


 Che stampa 1. mi suona un po' contradditorio.
Ciao Jack



Sei sicuro ? Lo hai provato ?
Max

> *Jack*: Risposta Esatta, motivazione sbagliata.
J> Tutta la pappardella dei miei altri post
J> e' giusta...parzialmente.
Ni. In  Java il tipo della  variabile che contiene  il riferimento NON
influenza il tipo dell'oggetto cui "punta" il riferimento che conserva
il SUO  tipo come,  guardacaso(*) in  LISP. La cosa  è nota  come late
binding. 
(*) "Andavamo dietro ai programmatori  C++ e li abbiamo portati a metà
     strada verso il LISP." G. Steele, coautore della JVM e autore del
     libro Common LISP, the Language.
Il cast fa "accettare" al compilatore l'assegnazione del contenuto di
una variabile di tipo A ad una variabile di tipo B, ma a runtime viene
ancora fatto il controllo che può terminare in una ClassCastException.
Qui NON capita perché C è sia un A che un B.
J> ma la domanda d'esame era piu' subdola.
Domanda da certificazione...
Sembrano domande del cavolo, ma a volte è lì che c'è il comportamento
anomalo del programma...
J> B.f() e' private e non public.
Te ne sei accorto :).
Ecco cosa dice javap riguardo a B
saint@gastone:~/java$ javap -c -private B
Compiled from "Main.java"
class B extends A{
B();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method A."<init>":()V
   4:   return
private int f();
  Code:
   0:   iconst_1
   1:   ireturn
public int g();
  Code:
   0:   aload_0
   1:   invokespecial   #2; //Method f:()I
   4:   ireturn
}
Essendo f() private, il compilatore evita di mettere una invokevirtual
in g()  e mette una invokespecial. La  cosa ha senso, se  ci pensi. Il
programmatore ha  messo del  codice in un  metodo privat  separato per
leggibilità, non perché possa essere sostituito!
-- 
 /\           ___
/___/\_|_|\_|__|___Gian Uberto Lauri_____
  //--\| | \|  |   Integralista GNUslamico
\/                 e coltivatore diretto di Software
A Cesare avrei detto di scrivermi a 
fn...@rat.vg

 }
C'è il trabocchetto :)
Le f() di A e B sono private; quella definita in C NON è quindi un 
override (i membri privati non sono visibili alle sottoclassi).
Quindi stampa 1, semplicemente perché l'unica versione di f() 
disponibile dentro la chiamata g() di B è proprio quella di B.
Per controprova basta ridefinire gli f() come pubblici per ottenere 2.
pole
-- 
ammentos - a lightweight persistence framework for JDK5
http://ammentos.biobytes.it
Flash tutorial: 
http://ammentos.biobytes.it/quickstart/quickstart.html

 Max
invece di rompere le balle. tu lo hai provato?
Ciao Jack

 Tra l'altro anche CarMas ha risposto 1, ma gliel'hai data sbagliata.
si hai ragione, scusami.
C'era qualcosa di evidentemente sbagliato visto che sia tu che CarMas 
avevate dato la stessa risposta, e ve ne avevo data una buona ed una 
sbagliata! :)

 MEGACUT
Questa č la risposta giusta, e mi sembra spiegata molto meglio di quanto 
avrei saputo fare io.
Anche qualcun altro ha dato una buona motivazione, ma ho paura di 
dimenticarmi qualcuno, quindi non li elenco! :)
Se penso ai colleghi che hanno risposto 1 senza sapere il perché.. :(
Vabbč.. fortunati loro..
Per quanto riguarda la domanda sulle interfacce, la cosa interessante 
era che, c'era un conflitto perché esistevano due variabili con lo 
stesso nome, ma la cosa bella (e questo mi ha fregato, perché prima 
dell'esame io avevo provato a fare una cosa del genere..) č che non 
viene segnalato alcun errore di compilazione sino a quando il conflitto 
non "scoppia", ovvero fino a quando non viene utilizzata quella variabile.
Io infatti, al termine dell'esame dissi al mio caro prof.:
"guardi, sono sicuro che se la utilizzo, mi da errore di compilazione.."
e lui:
"ma guarda che nella risposta si parla semplicemente di conflitto, non 
di errori di compilazione.."
e io:
"ma sux.." <-- questa non č vera ;)
Comunque fare queste domande ad un esame, con poco tempo a disposizione 
per rispondere, č una bastardata IMHO, perň sono domande interessanti, 
lo devo ammettere.
Saluti,
ah, mi dimenticavo, diamo un bel 30 a tutti, cosě siamo tutti felici e 
contenti ;)
--
il 7

 binding.
ah ecco. la cosa cmq e' anomala, nel senso che va un po' contro la
logica (mia perlomeno).
ma visto che deriva dal LISP la cosa non mi stupisce piu' di tanto :)
Ciao Jack

> MEGACUT
i7> Questa è la risposta giusta, e mi sembra spiegata molto meglio di
i7> quanto avrei saputo fare io.
Magari c'è un perché :>
i7> Per quanto riguarda la domanda sulle interfacce, la cosa
i7> interessante era che, c'era un conflitto perché esistevano due
i7> variabili con lo stesso nome, ma la cosa bella (e questo mi ha
i7> fregato, perché prima dell'esame io avevo provato a fare una cosa
i7> del genere..) è che non viene segnalato alcun errore di
i7> compilazione sino a quando il conflitto non "scoppia", ovvero fino
i7> a quando non viene utilizzata quella variabile.
Non esiste un conflitto. Non esiste proprio, niente conflitto, niente,
nada, nicht, niet.
Esistono invece usi ambigui.
Veniamo al  tuo caso (semplificato)  usando per brevità il  package di
default.
interface I1 {
   // Questo definisce la costante I1.X
   int X = 0;
}
interface I2 {
   // Questo definisce la costante I2.X
   // È una costante diversa dalla precedente
   int X = 1;
}
public class Foobar {
    public static void main(String[] args) {
        // OCCHIO AL BOTTO!
        //
        // A questo punto il compilatore non sa che pesci pigliare,
        // il codice qui sotto rende il riferimento ambiguo dato che
        // ci sono due classi che mi espongono una costante X nel
        // package. Soluzione, indicare il nome completo della
        // costante... 
        System.out.println(X);
    }
}
Peraltro, esistono  in rete vari package che  offrono costanti, metodi
ed  anche  classi  con  lo  stesso  nome,  anche  nella  distribuzione
ufficiale.
Date data;
La variabile  data sarà java.util.Date  o java.sql.Date ?  E' ambiguo,
non c'è una sola scelta.
In  un  programma  vero,  il  programmatore sceglie  quale  delle  due
implementazioni  utilizzare, e  questo lo  fa a  seconda  dell'uso che
dovrà farne (purtroppo capitano anche delle scelte a caso, sono i tuoi
colleghi che hanno passato l'esame per pura fortuna...), il compito di
sciogliere l'ambiguità è comunque suo, come nel caso del tuo esercizio
di esame.


Rispondo all' ultima domanda, che è piu interessante.
la risposta corretta è la E.
il punto che l'overriding esiste per i metodi e non per le variabili.
vediamo cosa implica:
[code]
I1   i1  = new A();
I1   i2 = new A();
System.out.println(i1.VAL_B); // stampa 2; perchè i1 è dichiarato come
I1
System.out.println(i2.VAL_B); // stampa 3; perchè i2 è dichiarato come
I2
[/code]
Stefano

> come late binding.
J> ah ecco. la cosa cmq e' anomala, nel senso che va un po' contro la
J> logica (mia perlomeno). 
Sicuramente  è  anomala pensando  in  C.  Ma  C  non  è un  linguaggio
"fortemente  tipizzato",  la  tipizzazione  è tutta  nella  mente  del
programmatore.
In C  dico che una  variabile è  un float e  quindi una certa  area di
memoria, dall'indirizzo X all'indirizzo Y viene interpretata come tale
e se  ci faccio sopra dell'aritmetica  quei bit vengono  presi come un
float IEEE.
In Java  dici che una  certa variabile è  di tipo SomeObject.   
Ovvero dichiari  che vuole dire che contiene  un riferimento (potrebbe
essere  la chiave in  un DB  relazionale...)  ad  un oggetto  che deve
comportarsi come un SomeObject.
(Ma che nessuno vieta  sia in realtà MeravigliosoNovissimo che estende
StupendoEccezionale   che  estende   GranBellaCosa  che   ...  estende
SomeObject).
E tu potrai  invocarci solo i metodi definiti  da SomeObject. Anche se
l'oggetto mantiene la sua natura e le sue capacità.
Se  assegni a persona  una istanza  di ProgrammatoreJavaEsperto  o una
istanza di WebDesigner, potrai in ogni caso richiedere 
persona.ripulisciTag(file)
per ogni file di una collezione. Ma la persona fisica cui la variabile
si riferisce rimane un ProgrammatoreJavaEsperto o un WebDesigner.
/* 
   Probabilmente sei in un blocco 
   catch (ProblemiDiGestioneException e)
*/
j>  ma visto che deriva dal LISP la cosa non
J> mi stupisce piu' di tanto :)
Il LISP è una fonte di illuminazione, miscredente! :)



1. Innanzi tutto io non sono stato aggressivo e maleducato.
2. Certamente che l'ho provato, ed è per questo che ti dico che
sbagli.
Mi sa tanto che sei un Troll, per cui non darò seguito ai tuoi post.
Saluti
Max

 lasciare non implementato il metodo.
Scusa... ma non sono d'accordo.
Se il codice di cui discutiamo e' il seguente
abstract class A implements I1, I2 {
    public void f() {}
    public void g() {}
}
interface I1 {
    int VAL_A = 1;
    int VAL_B = 2;
    void f();
    void g();
}
interface I2 {
    int VAL_B = 3;
    int VAL_C = 4;
    void g();
    void h();
}
qui non c'e' assolutamente nulla di sbagliato!
I problemi (dati dall'ambiguita') ci saranno quando vai ad usarli... ma qui mica li usi, per cui io confermo la risposta E. 
Tra l'altro, mi pare che leggendo quanto scritto da Gian Uberto Lauri e Stefano siamo d'accordo su questo punto!
Saluti
CarMas

 
Ma lol! Ma usi una versione custom della JVM? Quella roba stampa
"sono un panda"
Mi sa tanto che sei tu quello a non averla provata...
Ciao
Co

Jack ha scritto:

Si, e stampa "sono un panda"

 Esistono invece usi ambigui.
Penso che nel contesto (NB: la domanda non l'ho fatta io, io ero quello 
che doveva rispondere!) ambiguità e conflitto siano usati come sinonimi.
Ma ora che leggevo la tua risposta, dove tu dici che per risolvere 
l'ambiguità era necessario utilizzare il "nome completo della costante", 
ho provato a farlo, utilizzando la dot notation e funziona.
Io all'esame così le dissi! E la mia prof. mi disse che per utilizzare 
la dot notation bisognava istanziare "oggetti di tipo interfaccia"..
Mannaggia, io dissi "si avete ragione", ma mi sa che.. :(
Per tutti quelli che insistono per la "E" (Non c’e' nulla di sbagliato), 
beh.. boh!
Secondo me, era poco precisa la domanda, e poco precise le risposte.
E' un po' ambiguo l'uso della parola conflitto al posto di ambiguità.. ;)
Mah! :/
Per correttezza\completezza riporto anche la risposta alla prima 
domanda, di un altro docente della mia università, che è co-autore delle 
domande:
Copioincollo:
************************************
C'e' da chiedersi che succede quando viene compilata la classe B.
  * Il compilatore incontra l'invocazione f() e deve decidere se 
risolvere esso stesso il legame con il metodo oppure rimandare al 
momento dell'esecuzione (invocazione virtuale di metodo).
  * Poiché il metodo invocato è privato in B, il compilatore decide che 
non può essere sovrapposto da una sottoclasse di B (ricordate? un metodo 
può essere sovrapponibile se è almeno visibile nella sottoclasse).
  * Pertanto il compilatore non può che risolvere al momento il legame e 
collega quella invocazione con il metodo f() della classe B.
Riguardo alla ereditarietà di attributi o metodi privati:
  * Alcuni autori affermano che tali attributi o metodi non siano 
ereditati dalle sottoclassi.
  * Altri preferiscono definire l'ereditarietà in modo opposto.
  * Io preferisco, per motivi didattici, dire che le classi non 
ereditano nulla; esse sono una formalizzazione di un tipo (in pratica 
sono blocchi statici di codice); esse sono utilizzate per la costruzione 
degli oggetti, nel cui processo interviene il meccanismo di ereditarietà 
ben noto triste.
  * A suffragare la mia tesi, questo esercizio mostra che l'oggetto, del 
tipo C (sottotipo di B), possiede due f(), una propria ed una ereditata 
da B(ma inaccessibile dal codice di C); è proprio questa f() 
inaccessibile che tuttavia viene utilizzata per risolvere l'invocazione 
di f, poiché tale invocazione avviene nel corpo di g() che è del tipo B.
  * Il motivo didattico della scelta è relativo al fatto che a me preme, 
più che discutere di questioni di lana caprina sulla natura del sesso 
degli angeli, che sia ben chiaro il meccanismo di costruzione degli 
oggetti ed il meccanismo di invocazione virtuale di metodi. Punto.
************************************
Mi fermo qui con sta storia, perché non è giusto divulgare così le cose, 
senza che gli autori ne siano a conoscenza. :)
Grazie, è stato interessante!
Saluti a tutti,
il 7

> Esistono invece usi ambigui.
i7> Penso che nel contesto (NB: la domanda non l'ho fatta io, io ero
i7> quello che doveva rispondere!) ambiguità e conflitto siano usati
i7> come sinonimi.
Qui  sbagli.  C'è  un  conflitto   quando  le  due  cose  non  possono
coesistere.   C'è  ambiguità quando  non  è meccanicamente  decidibile
quale di due alternative lecite scegliere.
i7> Ma ora che leggevo la tua risposta, dove tu dici che per risolvere
i7> l'ambiguità era necessario utilizzare il "nome completo della
i7> costante", ho provato a farlo, utilizzando la dot notation e
i7> funziona.
i7> Io all'esame così le dissi! E la mia prof. mi disse che per
i7> utilizzare la dot notation bisognava istanziare "oggetti di tipo
i7> interfaccia"..
Qui sbaglia la prof. Gli attributi nelle costanti sono automaticamente
public static final. Quindi corrispondono in modo biunivoco ad oggetti
concreti  ed  il  cui  valore   è  noto  al  momento  del  caricamento
dell'interfaccia - per le classi il valore deve essere noto all'uscita
del costruttore.
Anzi, non solo  la dot notation funziona con le  costanti, ma va anche
usata  necessariamente quando  le costanti  sono definite  in un'altra
classe/interfaccia.
É poco  usata, ma è una  tecnica lecita quella di  mettere le costanti
simboliche di progetto in una interfaccia e non in una classe.
i7> Per tutti quelli che insistono per la "E" (Non c’e' nulla di
i7> sbagliato), beh.. boh!  Secondo me, era poco precisa la domanda, e
i7> poco precise le risposte.  E' un po' ambiguo l'uso della parola
i7> conflitto al posto di ambiguità.. ;)
La domanda è chiarissima.
Riguardiamola
// Cosa c’`e di sbagliato nel codice seguente?
/* Va letto come: perché questo codice non si compila */
abstract class A implements I1, I2 {
   public void f() {}
   public void g() {}
}
interface I1 {
   int VAL_A = 1;
   int VAL_B = 2;
   void f();
   void g();
}
interface I2 {
   int VAL_B = 3;
   int VAL_C = 4;
   void g();
   void h();
}
A. La classe A non puo' implementare due interfacce.
   /* Si, ed allora perché Gosling le ha messe in Java, mi chiedo :)
      questa serve a segare chi non ha studiato per niente */
B. La classe A non ha fornito l’implementazione del metodo h()
   dell’interfaccia I2. 
   /* trappola, devi vedere l'abstract nel codice */
C. C’e' un conflitto delle dichiarazioni dei due metodi g() nelle
   interfacce I1 e I2.
   /* semitrappola, devi saper che classi diverse possono avere
      metodi con la stessa firma - vale anche per le interfacce.
      "conflitto" è chiaramente qualcosa che ferma la compilazione */
D. C’e' un conflitto delle dichiarazioni degli attributi VAL_B nelle
   interfacce I1 e I2. 
   /* semitrappola, devi sapere che classi e interfacce possono avere
      attributi pubblici con lo stesso nome e lo stesso tipo */
E. Non c’e' nulla di sbagliato.
   /* Risposta esatta, il programma viene correttamente compilato */
i7> Per correttezza\completezza riporto anche la risposta alla prima
i7> domanda, di un altro docente della mia università, che è co-autore
i7> delle domande:
A naso le  hanno copiate dagli esercizi di  certificazione. La puzza è
quella. :)
i7>  * A suffragare la mia tesi, questo esercizio mostra che
i7> l'oggetto, del tipo C (sottotipo di B), possiede due f(), una
i7> propria ed una ereditata da B(ma inaccessibile dal codice di C); è
i7> proprio questa f() inaccessibile che tuttavia viene utilizzata per
i7> risolvere l'invocazione di f, poiché tale invocazione avviene nel
i7> corpo di g() che è del tipo B.
Ah,  meno male  che non  fa  questioni di  lana caprina.  Non ci  sono
questioni teoriche,  c'è come è fatta  una macchina. Qui  sotto c'è il
bytecode (che è legato al sorgente in modo praticamente biunivoco).
class A extends java.lang.Object{
A();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
                            //Usa invokespecial perché SA a priori
                            //che metodo chiamare, quello di Object
   4:   return
private int f();
  Code:
   0:   iconst_0
   1:   ireturn
public int g();
  Code:
   0:   iconst_3
   1:   ireturn
}
class B extends A{
B();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method A."<init>":()V
                            //Anche qui si sa precisamente che metodo
                            //chiamare, quello di A. Che poi chiamerà
                            //quello di Object... Si, per ogni classe
                            //che crei alla fine vai a chiamare un
                            //costruttore di Object
   4:   return
private int f();
  Code:
   0:   iconst_1
   1:   ireturn
public int g();
  Code:
   0:   aload_0
   1:   invokespecial   #2; //Method f:()I
                            //Il compilatore ha trovato un metodo
                            //privato che soddisfa la firma ed usa
                            //quello - di nuovo invokespecial
   4:   ireturn
}
class C extends B{
C();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method B."<init>":()V
                            //Ed ecco il metodo di C
                            //che chiama quel di B, 
                            //che chiama quel di A,
                            //che chiama quel di Object
                            //che al mercato Gosling comprò...
                            //Alla fiera dell'Est... (*)
   4:   return
public int f();
  Code:
   0:   iconst_2
   1:   ireturn
}
public class Main extends java.lang.Object{
public Main();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
                            //Main estende Object direttamente...
   4:   return
public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class C
   3:   dup
   4:   invokespecial   #3; //Method C."<init>":()V
                            //Devo ricominciare con la canzoncina ?
   7:   astore_1
   8:   aload_1
   9:   checkcast       #4; //class B
                            //Questo verifica che noi non si sia
                            //scritto un casting a pera...
   12:  astore_2
   13:  getstatic       #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   16:  aload_2
   17:  invokevirtual   #6; //Method B.g:()I
                            //invokevirtual, qui non sa ancora cosa
                            //deve fare, quello che accade è descritto
                            //in dettaglio in questa pagina:
//
http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc6.html
   20:  invokevirtual   #7; //Method java/io/PrintStream.println:(I)V
   23:  return
}
Non c'è nessun metodo f() inacessibile in C. Tu ne vedi uno ?
Certe parole fanno solo confusione.
Bastava dire  che, dato che tutti  i metodi in Java  sono virtuali, al
momento di chiamare g() su un'istanza  di C, la JVM si mette a cercare
tra gli antenati di C qual'è il primo che presenta una implementazione
di g() per usare quella; a questo punto si spiegava ulteriormente che,
dato che  f() in  B è dichiarato  privato -  e quindi non  soggetto ad
override - la risoluzione era già avvenuta in fase di compilazione.


 [...]
E' chiaro.
Grazie mille!
Saluti,
il 7

 Max
ottimo, cosi non mi sento in colpa a killarti.


> è quella. :)
i7> Non mi esprimo! Non lo so! :)
Io  si... Ti  consiglio, se  ti interessa  diventare  un programmatore
Java, di  cercare in qualche modo il  libro di Sierra e  Bates per gli
esami  310-035  e 310-027  della  Osborne  Press.   Siccome penso  sia
caruccio (ma  niente sostituisce i  tomi di carta), prova  con qualche
strana mulattiera... O alla peggio chiedi aiuto a Cesare...
i7> Ok è chiaro.  Ma il punto è che io, non mi son mai preoccupato di
i7> guardarmi il bytecode di una mia applicazione, e soprattutto, non
i7> immaginavo minimamente che le cose funzionassero così.
Io  ho un  passato da  sistemista, ed  ho fatto  una  certa esperienza
accademica  con il codice  macchina. Penso  che, nonostante  tutto, il
sapere  cosa  succede  sotto  sia  una  cosa che  serve  molto  ad  un
professionista.
i7> Alla luce di ciò che m'hai detto, se ho capito bene, un C (nel
i7> nostro caso) continua a "possedere" tutti i metodi delle classi
i7> che estende.  Giusto?
Esatto. È per questo che si  parla di ereditarietà e di metodi virtual
(in italiano tradotto  non pertettamente con virtuale) . C  *è* un B e
conserva la sua natura di B laddove non la altera ridefinendo i metodi
virtuali.
