Enrera
Mòdul 4
Iniciació a la programació en Java
  Pràctica
1
2
3
4
   
Exercicis
Exercicis
 
 
  Objectes i classes (I)
   
  Creació i destrucció d'objectes:
   
La característica que ha donat més personalitat a Java en els darrers anys és l'absoluta orientació del llenguatge als objectes. Ja hem dit què a Java tot són classes i objectes (instàncies de les classes). Un cop hem après la metodologia bàsica de treball amb el llenguatge, hem d'aprofundir en les característiques dels objectes de Java, abans d'emprendre tasques de més complexitat.

Per tant, un objecte és una instància d'una classe. Té un estat i un funcionament. Té unes variables i uns mètodes. L'estat és definit per les variables membre, el funcionament el descriuen els mètodes. Hi ha dos grans grups de variables: les variables d'instància i les variables de classe:

  • Variables d'instància: Són variables que tenen un valor diferent per a cada objecte que creem a partir d'una classe.

  • Variables de classe: Són variables compartides per tots els objectes que són d'una classe. Per tant, el valor d'aquestes variables és el mateix per a tots els objectes de la classe. Aquestes variables, com veurem en aquesta pràctica, són static.

Un objecte Java es crea en tres passos, de la mateixa manera que a C++ i Object Pascal:

  • Es declara: se li dóna un nom.

  • S'instancia: se li assigna memòria

  • S'inicialitza: es donen valors inicials a les variables d'instància. Les variables de classe poden tenir valor abans de la instanciació d'un objecte particular.

Declarem un objecte amb una sentència com la següent :

<modificador> <nom de la Classe> <nom de l'Objecte>;

Per exemple,

public String Nom;

o

public Llibre unLlibre;

o

private Automovil unTaxi;

Aquestes sentències identifiquen objectes, però no assignen memòria.

La fòrmula habitual, no exclusiva, d'instanciar un objecte és la següent:

<nom de l'Objecte> = new <nom de la Classe>();

Per exemple,

Nom = new Nom();

unLlibre = new Llibre();

unTaxi = new Automovil()

És clar que habitualment declararem i instanciarem d'un cop:

public Edifici casameva = new Edifici();

i també declararem, instanciarem i inicialitzarem a la vegada

public Edifici casaMeva = new Edifici("palau");

Acabo de crear un objecte Edifici, al qual li he assignat memòria i li he passat un paràmetre que ens en descriu el tipus: un palau. El paràmetre li passo a través d'un mètode constructor (els repassarem en aquest mòdul).

A vegades, no ens farà falta ni donar nom als objectes, podem instanciar-los directament. Per exemple, aquest programa és completament correcte:

class diaAvui {

    public static void main(String args[]) {
        System.out.println(new java.util.Date()); // Instanciació
                                                  // d'un objecte
                                                  // java.util.Date
                                                  // sense donar-li
                                                  // nom!

    }

}

La metodologia de destrucció en memòria dels objectes és bastant peculiar, diferent de la emprada en llenguatges com C++ o Object Pascal. En aquests llenguatges quan un objecte ja no s'utilitza, s'allibera explícitament la memòria que ocupa mitjançant destructors.

Però a Java l'objecte que ja no s'utilitza queda anul·lat per la Màquina Virtual i passa a una llista d'objectes a eliminar. Per sota, un procés de baixa prioritat, que rep el nom de reciclador de memòria (Garbage Collector o GC) és l'encarregat d'alliberar la memòria dels objectes de la llista. El programador no s'ha d'ocupar de la gestió de recursos, sinó que és la pròpia Màquina de Java qui fa aquesta feina. En teoria, aquest mecanisme ha de permetre una utilització òptima de la memòria de l'ordinador. En la major part dels casos, especialment en programes senzills, succeix així. Com no hi res perfecte, ens podem trobar amb programes escrits en Java que van consumint memòria: en alguna part del procés el GC pot oblidar-se de recollir les escombraries!

El funcionament del GC és força curiós: és un fil (thread, vegeu el mòdul 7) de baixa prioritat. Aquest fil s'activa en determinats contextos: quan la màquina detecta que queda poca memòria, quan nosaltres li demanem que s'activi amb el mètode System.gc() o quan la màquina no està fent res perquè el sistema està ocupat en un altre procés.

Curiosament, encara que activem el GC explícitament, no tenim cap garantia de que s'alliberi la memòria perquè les decisions sobre què s'ha d'alliberar les pren el propi GC.

En aquest exemple podem veure com un objecte és creat i com el passem a la llista d'objectes anul·lats:

class elGc{
    public static void main(String args[]) {
        // Creem un objecte String instrument
        String animal= "gos";
        System.out.println(animal);
        // L'objecte string amb el contingut "gos"
        // s'anul·la i se'n crea un de nou amb el contingut "gat"
        // El piano queda en mans del gc. Segurament, la propera
        // vegada que s'activi el gc, d'aquí uns segons!,
        // l'espai de memòria del gos quedarà lliure.

        animal = "gat";
        System.out.println(animal);
    }
}
   
Atenció !

Tots els objectes tenen un mètode que ens permet actuar immediatament abans que el GC restitueixi la memòria: és el mètode protected void finalize(), de la classe java.lang.Object, la classe mare de tots els objectes de Java. Si sobreescrivim (override) aquest mètode, podem fer coses just en l'instant anterior que el propi objecte mori.

Comprovem-ne el funcionament. Escrivim aquests dos petits programes:

   

class Instrument{

    String nom;

    public Instrument(String nom) {
        this.nom = nom;
    }

    // Abans d'alliberar la memòria, escriure a la consola quin
    // objecte s'allibera

    protected void finalize() {
        System.out.println("alliberat l'objecte "+nom);
    }

}


class Memoria {

    public static void main(String[] args) {
        Instrument instrument = new Instrument("piano");
        System.out.println(instrument.nom);
        instrument = new Instrument("flauta");
        System.out.println(instrument.nom);
        instrument = new Instrument("clarinet");
        System.out.println(instrument.nom);
        // Executem el gc
        System.gc();
    }

}

 

Escriviu els programes en dos fitxers diferents Instrument.java i Memoria.java. Compileu i executeu Memoria.java. La sortida serà com aquesta:

   
 
   
  Hem creat un instrument amb el nom de piano. Seguidament hem creat una nova instància de l'instrument que es diu flauta. Llavors, piano ha quedat anul·lat i ha passat a la llista negra del GC. Sobre flauta construim clarinet i enviem flauta a la llista d'objectes anul·lats. Si passem el GC, el programa ens informa que acaba d'eliminar piano i flauta de la memòria. L'objecte clarinet continua viu fins al final del programa, moment en el qual serà destruït.
   
   
 
Amunt