www.isidoroghezzi.net

Java: subdolo errore (1/2)

descrizione tecnica e soluzione per codice ex novo
19 dicembre 2007
Un subdolo errore può essere facilmente commesso in Java, specialmente da parte di quei programmatori che vi si avvicinano, senza una solida esperienza di programmazione ad oggetti in C++. Subdolo perché spesso non viene riconosciuto in quanto tale, con catastrofiche conseguenze nello sviluppo successivo, di classi derivate da classi che lo contengono.

In questo articolo vi mostrerò l'errore, e come evitare di commetterlo.
Nel prossimo vi svelerò l'arcano, che vi permetterà di conviverci, nello sfortunato caso in cui dobbiate lavorare con una gerarchia di classi, che lo contengano diffusamente, mediante una tecnica assolutamente non invasiva, con lo scopo di non inficiare i test di validazione effettuati sul framework in oggetto.

L'errore:
Analizzate il seguente codice:
<?php
/*
    "XConstructorWrong.java"
    Copyright 2007 - 2008 isidoro ghezzi
    Compiled with: javac 1.5.0_13
    Tested with:
    java version "1.5.0_13"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05-237)
    Java HotSpot(TM) Client VM (build 1.5.0_13-119, mixed mode, sharing)
*/

abstract class XBase{
    abstract protected 
void init ();
    public 
XBase (){
        
init ();
    }
}

class 
XDerivate extends XBase{
    private 
String fWelcomeMessage "not initialized";
    public 
XDerivate (String theWelcomeMessage){
        
fWelcomeMessage theWelcomeMessage;
    }
    protected 
void init (){
        
System.out.println (fWelcomeMessage);
    }
}

public class 
XConstructorWrong {
    public static 
void main(String args []){
        
XBase aBase = new XDerivate ("Hello from XDerivate");
    }
}
?>
Che output vi aspettereste di avere?
Pensateci un attimo; nella prossima riga scriverò l'output generato, nudo e crudo:
null
Non scrive "Hello from XDerivate" e neppure "not initialized"!
L'errore nasce dalla possibilità, concessa in Java ed altri linguagi (non in C++) d'invocare metodi derivabili, direttamente o no, nel costruttore di una qualunque classe.

Descrizione tecnica dell'errore:
Il costruttore della base, viene eseguito prima dell'esecuzione del costruttore del figlio, quindi l'invocazione, nel costruttore del padre, di un metodo derivato, in generale opererà su dati del figlio che ancora non è stato costruito, generando pertanto comportamenti indefiniti.
In C++ il problema non sussiste, infatti nei costruttori (e distruttori) il meccanismo virtuale non viene applicato e, ad esempio, l'analogo codice di cui sopra in C++, non viene neppure compilato.

Soluzione per codice ex novo:
Per evitare l'errore, bisogna scrivere i costruttori in modo che in essi non vengano invocati metodi derivabili, ed eventualmente delegare l'invocazione di metodi derivabili a metodi anch'essi derivabili, invocati dopo l'instanzazione dell'oggetto.
Ad esempio:
<?php
/*
    "XConstructorGood.java"
    Copyright 2007 - 2008 isidoro ghezzi
    Compiled with: javac 1.5.0_13
    Tested with:
    java version "1.5.0_13"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05-237)
    Java HotSpot(TM) Client VM (build 1.5.0_13-119, mixed mode, sharing)
*/

abstract class XBase{
    abstract public 
void init ();
    public 
XBase (){
    
// Now the constructor is not calling an overridden method
    
}
}

class 
XDerivate extends XBase{
    private 
String fWelcomeMessage "not initialized";
    public 
XDerivate (String theWelcomeMessage){
        
fWelcomeMessage theWelcomeMessage;
    }
    public 
void init (){
        
System.out.println (fWelcomeMessage);
    }
    
    static 
XDerivate newInitialized (String theWelcomeMessage){
    
//
    // Returns a new and initialized XDerivate object.
    // Observe that the init method is called out of constructor.
    //
        
XDerivate ret = new XDerivate (theWelcomeMessage);
        
ret.init ();
        return 
ret;
    }
}

public class 
XConstructorGood {
    public static 
void main(String args []){
        
XBase aBase XDerivate.newInitialized ("Hello from XDerivate");
    }
}
?>
Se tale approccio è valido per una gerarchia di classi scritta ex novo, purtroppo non è applicabile, per motivi di validazione, a framework esistenti, su cui voi sfortunatamente, magari in questo momento, dovete lavorare, con la necessità di derivare da classi, che nel proprio costruttore malauguratamente invocano metodi derivabili.
Come comportarsi quindi in tali casi? Per prima cosa bisogna segnalare l'errore al responsabile del framework, nel frattempo convivere, derivando per delega attraverso una tecnica assolutamente non invasiva, che vi sarà illustrata nel prossimo articolo.
isidoro punto ghezzi chiocciola icloud punto com
copyright 2006 - 2007 - 2008 - 2009 - 2010 - 2011 - 2012 - 2013 - 2014 - 2015 - 2016 - 2017 - 2018 - 2019, isidoro ghezzi
tutti i marchi citati sono di proprietà dei rispettivi proprietari
www.isidoroghezzi.net non è legato ad alcun ente: pubblico o privato, militare o civile.
www.isidoroghezzi.net è totalmente "demicrosoftizzato".
1MqUrGb6SiebJ6tJZT272kbVQCryS6pFWd
1MqUrGb6SiebJ6tJZT272kbVQCryS6pFWd

Valid HTML 4.01 Transitional Valid CSS!