Fonction recursive et parametre

Signaler
Messages postés
718
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
22 novembre 2016
-
Messages postés
177
Date d'inscription
jeudi 5 octobre 2006
Statut
Membre
Dernière intervention
16 janvier 2009
-
Bonjour tout le monde,

    Je suis débutant en Java, et j'ai un problème dont je n'arrive pas à me depatouiller ...

    J'ai une fonction recursive (qui s'appelle donc elle meme), et j'ai en paramètre un ( Integer i ) .
    Chaque fois que la fonction s'appelle j'incremente i, mais quand la fonction appellée est terminée, et que je remonte d'un niveau, je reviens à la valeur de i precedente (celle qu'avait i avant l'appel recursif).

    Pourtant en passant un objet (Integer) en paramètre, je suis cencé passer une reference, et donc si j'incremente la variable à l'interieure d'une methode, meme en sortant de cette methode, i devrait garder sa nouvelle valeur.
   
    Et en fait... non ? pourquoi à votre avis ?
   
    PS : Vous allez surement me demander le code, mais c'est assez long et dans un système proprietaire.
    S'il vous le faut vraiment je le posterai.
   
   
    Ce n'est pas réelement çà, mais schématiquement :
   
        public boolean Methode( Integer i )
        {
            // Code ..
            i++;
           
            if ( Methode( i ) )
            {
                // Code ...
            }
           
            // Code ...
            return true;
        }
   
    En vous remerciant par avance pour votre aide.

<!-- blocPrincipal -->
 /\_/\
( o.o ) ~ ElGuevel ~
 > ^ <

14 réponses

Messages postés
744
Date d'inscription
dimanche 1 avril 2007
Statut
Membre
Dernière intervention
9 mai 2010
8
Je en pense pas qu'en Jave on passe des références.
En C, cela aurait été facile à voir mais bon, en Java, je ne pense pas qu'on puisse passer une référence.
Il faut quelqu'un qui valide ou critique ma pensée ^^
c'est mieux pour toi [auteurdetail.aspx?ID=21762 elguevel]<hr size="2" width="100%" />C'est après des heures de codage que j'ai compris pourquoi les mecs de Java ont choisi une tasse de café comme logo!
Messages postés
718
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
22 novembre 2016
3
Ba quand on passe un objet en parametre il me semble que c'est la reference de cet objet et non une copie. Par contre si l'on passe un type de base (int, boolean, ..) là effectivement on passe une valeur. Est ce que qqn du monde Java peut confirmer et est capable de repondre à mon probleme :-( ?

<!-- blocPrincipal -->
 /\_/\
( o.o ) ~ ElGuevel ~
 > ^ <
Messages postés
2448
Date d'inscription
samedi 21 février 2004
Statut
Modérateur
Dernière intervention
29 janvier 2010
17
essai de mettre un peu plus de code pour voir ...

"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"
Messages postés
718
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
22 novembre 2016
3
C'est delicat car c'est une application professionelle, donc j'ai enlevé une bonne partie du code non-necessaire et les commentaires. Je color en bleu les parties concernées, et un commentaire en rouge situe le probleme.

    public boolean CreateEBOMSheet( Context context, WritableWorkbook workbook, DomainObject objetDepart, StringList objectSel, StringList relationSel, HashMap mInfoEnfant, WritableSheet sheetParent, Integer ligneParent ) throws Exception
    {
        MapList expand objetDepart.getRelatedObjects( context, "EBOM", "*", objectSel, relationSel, false, true, (short)1, "revision last", null );

        expand.sort("attribute[Component Location]", "ascending", "Stringpad");

        if ( expand != null && expand.size() != 0 )
        {
 
            String sIdObject     = (String) objetDepart.getAttributeValue( context, SELECT_ID );
            String sLibelle     = (String) objetDepart.getAttributeValue( context, "REELLibelle"    );
            String sNumeroPlan     = (String) objetDepart.getAttributeValue( context, "REELNumeroPlan" );
            String sMasse         = (String) objetDepart.getAttributeValue( context, "Weight" );
            String sIndice         = (String) objetDepart.getInfo( context, "revision" );
            String sCodeArticle = (String) objetDepart.getInfo( context, "name"  );
            String sEmetteur     = (String) objetDepart.getInfo( context, "owner" );

             String sPage = new String();
            int nbPage = workbook.getNumberOfSheets(); // Nombre de page
 
               if ( sLibelle.length() > 26 ) {
                sPage = String.valueOf(nbPage) + "-" + sLibelle.substring(0, 26);
            } else {
                sPage = String.valueOf(nbPage) + "-" + sLibelle.toString();
            }

            sPage = sPage.replace( '\'', ' ' );
            sPage = sPage.replace( '/', ' ' );
 
            workbook.copySheet( "Modele", sPage, nbPage );
            WritableSheet sheet = workbook.getSheet( nbPage );

            mInfoEnfant.put( "sObjectId", sIdObject );
            mInfoEnfant.put( "sPage",     sPage     );

            sheet.addCell( new Label( 10, 0, CompleteDate, BorderCellHeader ) ); // K1 : Date
            sheet.addCell( new Label( 4,  2, sLibelle,        BorderCellHeader ) ); // E3 : Libellé
            sheet.addCell( new Label( 4,  4, sNumeroPlan,  BorderCellHeader ) ); // E5 : Numéro de plan
            sheet.addCell( new Label( 4,  6, sCodeArticle, BorderCellHeader ) ); // E7 : Code article
            sheet.addCell( new Label( 10, 2, sIndice,        BorderCellHeader ) ); // K3 : Indice d'en-tete
            sheet.addCell( new Label( 10, 4, sEmetteur,    BorderCellHeader ) ); // K5 : Emetteur
            sheet.addCell( new Label( 10, 6, sMasse,        BorderCellHeader ) ); // K7 : Masse

            Integer i = new Integer(9);                                         // On commence à la ligne 10
            int iNbElements = expand.size();

            // Parcour toutes les lignes et les places
            for( int ligne = 0; ligne < iNbElements; ligne++ )
            {

                // Recupère les lignes de l'expand
                Map mapObject = (Map) expand.get(ligne);

                // Prépare à chercher des lignes sous l'article
                String idEnfant = (String) mapObject.get( SELECT_ID );
                HashMap infosEnfant = new HashMap();

                // *** On recupère les différents champs ***

                String sNfoCodeArticle        = (String) mapObject.get("name");
                String sNfoRevision            = (String) mapObject.get("revision");
                String sNfoAutoDescription     = (String) mapObject.get("attribute[REELAutomaticDescription]");
                String sNfoCommentaireMatrix= (String) mapObject.get("attribute[REELCommentaire]");
                String sNfoLibelle             = (String) mapObject.get("attribute[REELLibelle]");
                String sNfoNumeroDePlan        = (String) mapObject.get("attribute[REELNumeroPlan]");
                String sNfoMasse            = (String) mapObject.get("attribute[Weight]");
                String sNfoRepereArticle    = (String) mapObject.get("attribute[Component Location]");
                String sNfoUniteQt            = (String) mapObject.get("attribute[Unit of Measure]");
                String sNfoQuantite            = (String) mapObject.get("attribute[Quantity]");
                String sNfoMaterialCategory    = (String) mapObject.get("attribute[Material Category]");
                String sNfoNiveauPieceSecu    = (String) mapObject.get("attribute[REELPieceDeSecurite]");
                String sNfoPiecePG             = (String) mapObject.get("attribute[REELIdentifiantPieceSecurite]");
                String sNfoModeAppro         = (String) mapObject.get("attribute[REELModeApprovisionnement]");
                String sNfoCommentaireAppro = (String) mapObject.get("attribute[REELCommentaireModeApprovisionnement]");
                String sNfoNature              = (String) mapObject.get("attribute[REELNature]");

    if ( isDebit(sNfoRepereArticle, sNfoNature) )
                {

// C'est ici qu'est le probleme, j'incremente le paramètre, mais quand je sort de la fonction, le i du parent (donc ligneParent ici) revient à çà valeur d'origine.

                    ligneParent++;                   

                    sheetParent.addCell( new Label( 4, ligneParent, sNfoLibelle, WrapCellGrid ) );            // Libelle
                    sheetParent.addCell( new Label( 0, ligneParent, sNfoRevision, CenterCellGridDebit ) );  // Revision

                     // Champs non concernés par les liens
                    sheetParent.addCell( new Label( 1, ligneParent, sNfoRepereArticle, CenterCellGrid ) );    // Repère de l'article

                    // Unité de la quantité
                    if ( sNfoUniteQt.equalsIgnoreCase("PC") )
                    {
                        sheetParent.addCell( new Label( 2, ligneParent, sNfoQuantite, CenterCellGrid ) );   // Quantité
                    }
                    else
                    {
                        WritableCellFeatures wcfUnite = new WritableCellFeatures();
                        wcfUnite.setComment( "Unite : " + sNfoUniteQt.toString(), (double)0.9, (double)0.5 );
                        Label lUnite = new Label( 2, ligneParent, sNfoQuantite, CenterCellGrid );
                        lUnite.setCellFeatures( wcfUnite );
                        sheetParent.addCell( lUnite );    // Quantité
                    }

                    sheetParent.addCell( new Label( 5, ligneParent, (String) hmMatiereMap.get( sNfoMaterialCategory ), CenterCellGrid ) );  // Matière

                    // Piece de sécurité
                    if ( !sNfoNiveauPieceSecu.equals("Non") )
                    {
                        if ( sNfoPiecePG.equals("") ) { sheetParent.addCell( new Label( 3, ligneParent, sNfoNiveauPieceSecu, WrapCellGrid ) ); } else { sheetParent.addCell( new Label( 3, ligneParent, sNfoPiecePG, WrapCellGrid ) ); }
                    }
                    else
                    {
                        sheetParent.addCell( new Label( 3, ligneParent, "", WrapCellGrid ) );
                    }

                }
                else
                {

                    if ( CreateEBOMSheet( context, workbook, (DomainObject) this.getObject( context, idEnfant ), objectSel, relationSel, infosEnfant, sheet, i ) )
                    {
                        // CODE
                        // ...
                        // ...
                        // ...
                        // CODE
                    }

                    // CODE
                    // ...
                    // ...
                    // ...
                    // CODE

                    // Ligne suivante
                    i++;
                }

            }

            return true;
        }
        else
        {
            return false;
        }
    }

<!-- blocPrincipal -->
 /\_/\
( o.o ) ~ ElGuevel ~
 > ^ <
Messages postés
2448
Date d'inscription
samedi 21 février 2004
Statut
Modérateur
Dernière intervention
29 janvier 2010
17
ta essaye de metre ligne parent en static

je doit avouer que ton code est un peu gros lol ...
j'ai du mal a voir ... normalement en java on bosse par reference ... au pire essai de faire une miniclass de test de ce genre :

public classe monint {
int i ;
public monint(int i){
this.i = i;
}
public int geti(){return i;}
public void increment(){ ++i;}
}

ou alors je sais pas trop ...
"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"
Messages postés
718
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
22 novembre 2016
3
Je n'ai pas mis le reste du code car bcp seraient etonnné, déja c'est plein de classes proprietaires et les classes ont toutes comme prototype :

public class ${CLASSNAME} extends ${CLASS:emxDomainObject}

Donc je ne peut ecrire mon code que dans 1 seule classe.

> C'est en fait des scripts d'un PLM nommé Matrix. ( de chez Matrix One ).
 
Mais en gros à partir de l'arborescence de ce logiciel je genere un fichier excel qui comprend 1 onglet par niveau d'arborescence. Tout fonctionne mais on m'a demandé recement d'adapter le programme pour remonter des infos d'un certain niveau de 2 niveaux au dessus. D'où mon soucis de pouvoir interagir avec une variable d'une autre instance de ma fonction.

J'ai appris le Java y'a 2 mois sur le tas avec 1 bouquin en main, et si j'apprend vite, des concepts m'echappes comme cette histoire de reference qui n'en ai pas une à prioris !!?

<!-- blocPrincipal -->
 /\_/\
( o.o ) ~ ElGuevel ~
 > ^ <
Messages postés
2448
Date d'inscription
samedi 21 février 2004
Statut
Modérateur
Dernière intervention
29 janvier 2010
17
en fait les references en java peuvent etre parfois sujette a bug par exemple :

Vector<String> v = ......
Vector<String> j = v;

v.add(element); // a ete aussi ajoute dans v

"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"
Messages postés
177
Date d'inscription
jeudi 5 octobre 2006
Statut
Membre
Dernière intervention
16 janvier 2009
1
Bonjour,
je viens de tester un truc simple:
public class Test {
    private Integer i;
    public Test() {
        super();
        rec(0);
    }

    public static void main(String[] args){
        new Test();
    }
   
    public int rec( Integer i){
        i++;
        System.out.println("Valeur avant l'appel: " + i);
        if( i < 10)
            rec(i);
        System.out.println("Valeur après l'appel: " + i);
        return 0;
    }   
}

Et en effet après l'appel, i a garde la valeur de avant l'appel:
Voici la Console:
Valeur avant l'appel: 1
Valeur avant l'appel: 2
Valeur avant l'appel: 3
Valeur avant l'appel: 4
Valeur avant l'appel: 5
Valeur avant l'appel: 6
Valeur avant l'appel: 7
Valeur avant l'appel: 8
Valeur avant l'appel: 9
Valeur avant l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 9
Valeur après l'appel: 8
Valeur après l'appel: 7
Valeur après l'appel: 6
Valeur après l'appel: 5
Valeur après l'appel: 4
Valeur après l'appel: 3
Valeur après l'appel: 2
Valeur après l'appel: 1

Donc on peut en déduire, que java gère les classes enveloppes(Integer->int, Float->float) comme les types primitifs... ie
en passant la valeur...
Cordialement,
Pierrick
Messages postés
177
Date d'inscription
jeudi 5 octobre 2006
Statut
Membre
Dernière intervention
16 janvier 2009
1
Vous allez me dire comment faire alors ? -> Avec une variable globale...
public class Test {
    private Integer i;
    public Test() {
        super();
        i = 0;
        rec(  );
    }

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args){
        new Test();
    }
   
    public int rec(){
        i++;
        System.out.println("Valeur avant l'appel: " + i);
        if( i < 10)
            rec();
        System.out.println("Valeur après l'appel: " + i);
        return 0;
    }   
}

Resultat:
Valeur avant l'appel: 1
Valeur avant l'appel: 2
Valeur avant l'appel: 3
Valeur avant l'appel: 4
Valeur avant l'appel: 5
Valeur avant l'appel: 6
Valeur avant l'appel: 7
Valeur avant l'appel: 8
Valeur avant l'appel: 9
Valeur avant l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10

J'espère que ça peut t'aider...
Cordialement,
Pierrick
Messages postés
2448
Date d'inscription
samedi 21 février 2004
Statut
Modérateur
Dernière intervention
29 janvier 2010
17
test 1 :

public

class
test
{

public
static
void
main(String[]
args)
{

<gras>new

test();

}

public
test()
{

<gras>int

k
=
2;

System.out.println(k);

set(k);

System.err.println(k);

}

public
void
set (<gras>int
i){

i++;

}}

Sortie :
avant increment : 2

apres increment = 2

test 2 :

public

class
test
{

public
static
void
main(String[]
args)
{

<gras>new

test();

}

public
test()
{

<gras>int

k
=
2;

System.out.println("avant increment : "
+
k);

set(k);

System.err.println("apres increment = "
+
k);

}

public
void
set (<gras>int
i)
{

if(++i
<10)set(i);

}}

sortie :
apres increment = 2

avant increment : 2

pareil avex Integer au lieu de int

"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"
Messages postés
718
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
22 novembre 2016
3
Cà m'aide sans m'aider ...  car c'est plus complexe que çà.

Chacune de mes instances de fonction doit avoir une valeur de "i" propre,  mais elle doit etre modifiable à partir de l'instance "fils".

Si je fait une variable globale (ou un static), j'ai la meme variable "i" quelque soit l'instance de ma fonction, du coup plus aucun interet.

Je sais ... j'suis chiant, mais dans d'autres languages je n'aurai pas eut se probleme. :-s

<!-- blocPrincipal -->
 /\_/\
( o.o ) ~ ElGuevel ~
 > ^ <
Messages postés
177
Date d'inscription
jeudi 5 octobre 2006
Statut
Membre
Dernière intervention
16 janvier 2009
1
Re,
ce que tu dis n'est possible dans aucun langage....
Soit la fonction peut être accéder par toutes les fonctions --> IE elle est globale,
soit chaque fonction en possède une copie dans ses variables locales...
Je ne comprend pas clairement ce qui ne va pas... Des deux solutions, il y en a forcément une qui t'iras...
Cdlt,
Messages postés
718
Date d'inscription
jeudi 19 décembre 2002
Statut
Membre
Dernière intervention
22 novembre 2016
3
Faut que je reflechisse et que je fasse un exemple concret, j'arrive pas a m'exprimer je crois. Ou alors c'est moi qui me plante complétement ... comme je dit : "je debute".

Bon j'y reflechie, et je vous refait signe.

Sinon merci encore à tous pour vos nombreuses idées.

<!-- blocPrincipal -->
 /\_/\
( o.o ) ~ ElGuevel ~
 > ^ <
Messages postés
177
Date d'inscription
jeudi 5 octobre 2006
Statut
Membre
Dernière intervention
16 janvier 2009
1
Re salut,
Je pense t'avoir trouvé une solution, il te faut doubler le paramètre et que ce soit un objet(ie pas un type natif)
Ainsi au démarage les deux variables ont la même valeur, mais à la sortie de l'appel récursif tu récupère seulement la valeur modifiée par le premier appel:
public class Test {
    private class MyInteger{
        int i = 0;

        public MyInteger(int i) {
            super();
            this.i = i;
        }

        public MyInteger(MyInteger mi) {
            super();
            this.i = mi.getI();
        }
       
        public void inc(){
            i++;
        }
       
        public void dec(){
            i--;
        }
       
        public int getI() {
            return i;
        }

        public void setI(int i) {
            this.i = i;
        }

        @Override
        public String toString() {
            return String.valueOf(i);
        }
       
       
    }
    public Test() {
        super();
        rec( new MyInteger(0), new MyInteger(0) );
    }

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args){
        new Test();
    }
   
    public void rec( MyInteger i, MyInteger j){
        i.inc();
        j.inc();
        System.out.println("Valeur avant l'appel: " + i);
        if( i.getI() < 10){
            rec( j, new MyInteger(j) );
        }
        System.out.println("Valeur après l'appel: " + j);
    }   
}

Et cela donne enfin:
Valeur avant l'appel: 1
Valeur avant l'appel: 2
Valeur avant l'appel: 3
Valeur avant l'appel: 4
Valeur avant l'appel: 5
Valeur avant l'appel: 6
Valeur avant l'appel: 7
Valeur avant l'appel: 8
Valeur avant l'appel: 9
Valeur avant l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 10
Valeur après l'appel: 9
Valeur après l'appel: 8
Valeur après l'appel: 7
Valeur après l'appel: 6
Valeur après l'appel: 5
Valeur après l'appel: 4
Valeur après l'appel: 3
Valeur après l'appel: 2

Voilà msieur,
cordialement,