|   | 
    L'herència | 
  
   
    |   | 
      | 
  
   
    |   | 
    Avantatges de l'herència | 
  
   
    |   | 
      | 
  
   
      | 
     
       Quan Java va néixer, els dissenyadors 
        de llenguatges buscaven solucions per a fer la programació més 
        eficaç, més ràpida i més barata. L'antecedent 
        eren els llenguatges procedurals com 
        ara C. En aquell context,amb la finalitat 
        d'aprofitar el codi de programes anteriors, es copiaven les llibreries 
        ja escrites i s'adaptaven les funcions 
        que contenien a les noves necessitats. Funcionava, malgrat ser poc pràctic. 
      Es va pensar en l'herència com 
        una estratègia per a facilitar la reutilització 
        de codi. A Java, s'aprofita el 
        codi creant classes noves, però 
        no sobre el buit, sinó sobre altres classes 
        que, en molts casos, no cal ni tocar perquè s'adaptin a les noves 
        necessitats. La idea és simple: tenim un objecte 
        que fa una tasca i necessitem una adaptació per a resoldre un problema 
        nou o diferent. No tenim la necessitat obligatòria de fer una classe 
        completament nova, sinó que estenem 
        la que tenim a una classe filla que incorpora 
        noves funcionalitats o en reescrivim (override) 
        les de la classe mare. 
      L'herència no és tampoc 
        una solució màgica per a tot. De fet, exigeix al programador 
        una bona dosi de planificació abans de posar-se a escriure codi: 
        les virtuts de les classes es propaguen 
        a les classes filles, però també 
        els seus defectes. Un projecte Java amb 
        una planificació deficient o incorrecta pot convertir l'experiència 
        de codificació en un suplici. El consell és simple: repenseu-vos 
        sempre amb molta cura la forma i continguts que doneu a les vostres classes. 
      A partir d'aquesta pràctica aprendrem a manipular algunes de les 
        possibilitats de l'herència en Java. 
        Aprendrem a crear classes filles que 
        seran capaces d'ampliar o modificar 
        les capacitats de les classes mares i 
        els donarem plasticitat a través de la sobrecàrrega 
        de mètodes i de constructors. 
     | 
  
   
    |   | 
      | 
  
   
    |   | 
    Superclasses i Subclasses: | 
  
   
    |   | 
      | 
  
   
    |   | 
     
       La definició de l'herència és molt simple. Si escric 
        una classe nova que és descendent d'una classe que ja existeix 
        només he de dir: 
         
       
      
         
          class Nova extends 
            Vella { 
             
                ...  
             
            } | 
         
       
      Els membres no privats de la classe 
        mare passen a ser automàticament membres 
        de la classe filla. La classe mare 
        és la superclasse i la filla és 
        una subclasse.  
     | 
  
   
    |   | 
      | 
  
   
    |   | 
    Imaginem un centre escolar com un edifici que 
      agrupa diferents categories d'espais físics. Una expressió 
      simplificada d'aquesta realitat seria aquesta: | 
  
   
    |   | 
     
      
     | 
  
   
    |   | 
     
       Qualsevol espai del centre és un "objecte" 
        Espai, però no tots els espais es descriuen 
        de la mateixa forma: la cafeteria té 
        peculiaritats que no té una aula genèrica 
        o el despatx d'un departament. El gràfic 
        interpreta de forma jeràrquica les categories d'espais;disposem 
        d'aules i d'espais de treball dels professors. Les aules poden ser un 
        gimnàs, aules d'informàtica o laboratoris.  
      Aquesta estructura d'arbre es pot traduir fàcilment a diferents 
        classes vinculades per herència, 
        on la superclasse de totes és 
        "Espai". Un espai qualsevol té 
        un codi que l'identifica, una superfície, disposa o no de llum 
        natural, té un consum elèctric particular, etc. Un despatx 
        a més, té taules per als professors o màquina de 
        cafè. Aquest instrument no està instal·lat a les 
        aules, les quals, en canvi, tenen un aforament màxim o disposen 
        o no de cadires de pala. 
         
        Si codifiquem tot això podria quedar així: escriviu cadascuna 
        d'aquestes classes en el mateix fitxer: 
     | 
  
   
    |   | 
      | 
  
   
      | 
     
      
         
          |  
             class Espai { 
               
                  String codi; 
                  int metresquadrats; 
                  boolean llumnatural; 
                  int consumelectric; 
                public Espai() { 
                  }  
               
                  public Espai(String codi, int metres, boolean 
              llum, int consum) { 
                      this.codi = codi; 
                      this.metresquadrats=metres; 
                      this.llumnatural=llum; 
                      this.consumelectric=consum; 
               
                  }  
                public double consumM2() { 
                      if (metresquadrats>0) 
                          
              { return consumelectric/metresquadrats; }  
                      else  { return 
              0; } 
                  } 
             }  
           | 
         
       
     | 
  
   
    |   | 
     
      
         
          |  
             class Aula extends Espai { 
               
                  boolean cadiresdepala; 
                  boolean connectorsxarxa; 
                  int places;  
                  int ordinadors; 
               
                  public Aula() { 
                  }  
               
                  public Aula(String codi, int metres, boolean 
              llum, 
                              
              int consum, int places) { 
                      super(codi,metres,llum,consum); 
                      this.places=places; 
                  } 
               
                  public double espaiEstudiant() { 
                          if 
              (places>0) { 
                              
              return metresquadrats / places; 
                          
              } else { 
                              
              return 0; 
                          
              } 
                  } 
               
                  public double espaiEstudiant(int m, int 
              p) { 
                      this.places = p; 
                      this.metresquadrats 
              = m; 
                          if 
              (places>0) { 
                              
              return metresquadrats / places; 
                          
              } else { 
                              
              return 0; 
                          
              } 
                  } 
               
              }  
           | 
         
       
     | 
  
   
    |   | 
     
      
         
          class Despatx extends Espai 
            { 
             
                int taules; 
                boolean maquinadecafe; 
             
                public Despatx() { 
                }  
             
                public Despatx(String codi, int metres, 
                               
            boolean llum,int consum) { 
                    super(codi,metres,llum,consum); 
                } 
             
            } 
           | 
         
       
     | 
  
   
    |   | 
     
      
         
          class Laboratori extends Aula { 
             
                int bunsens; 
             
                public Laboratori() { 
                }  
             
                public Laboratori(String codi, int metres, 
            boolean llum, 
                      int
consum, int places) { 
                    super(codi,metres,llum,consum,places); 
                } 
             
            }  
           | 
         
       
     | 
  
   
    |   | 
     
      
         
          class Informatica extends Aula { 
                int impressores; 
             
                public Informatica() { 
                }  
             
                public Informatica(String codi, int metres, 
            boolean llum, 
                       int
consum, int places) { 
                    super(codi,metres,llum,consum,places); 
                } 
             
            } 
           | 
         
       
     | 
  
   
    |   | 
     
      
         
          |  
             class Gimnas extends Aula{ 
               
                  boolean dutxes; 
                  int grades; 
               
                  public Gimnas() {  
                  } 
               
                  public Gimnas(String codi, int metres, boolean 
              llum,  
                                      
int consum, int places) { 
                      super(codi,metres,llum,consum,places); 
                  }  
               
                  public double espaiEstudiant() { 
                      if (places>0) 
              { return (metresquadrats+grades) / places; }  
                          
              else { return 0; } 
                  } 
               
              }  
           | 
         
       
     | 
  
   
    |   | 
      | 
  
   
    |   | 
    La classe Espai 
      disposa de quatre variables (codi de l'espai, 
      superfície, disponibilitat de llum natural i consum elèctric 
      per hora). Aquestes variables estaran disponibles 
      per a qualsevol de les seves subclasses, 
      cadascuna de les quals també disposarà del mètode public 
      double consumM2(), un senzill mecanisme de càlcul que ens 
      permet saber quanta electricitat es consumeix en aquest espai per m2. 
      A més, la classe disposa de dos 
      constructors, un que inicialitza 
      les quatre variables i un altre que no n'inicialitza 
      cap. 
       D'aquesta superclasse hereten les classes 
        Aula i Despatx. Per 
        a les aules hem previst una utilitat específica, que no necessitarem 
        per les oficines o departaments: la disponibilitat d'espai per a cada 
        plaça d'estudiant (mètode public 
        double espaiEstudiant()). Pels espais "Despatx" 
        no hem previst cap càlcul específic, només el còmput 
        de taules i màquines de cafè. 
      Finalment, definim dues classes que 
        hereten de la classe Aula, 
        les classes Laboratori 
        i Gimnas. "Laboratori" 
        ens servirà per especificar les particularitats d'aquest tipus 
        d'espai: en el nostre cas, un comptador de bunsens. En el cas de Gimnas, 
        tot i ser una Aula, descobrim que el mètode 
        de la superclasse espaiEstudiant() no 
        ens serveix, perquè la superfície de la instal·lació 
        està dividida entre la pista i les grades. Per això n'hem 
        creat un mètode de càlcul específic: 
        hem sobreescrit (override) 
        un mètode de la superclasse. 
      Ara escriurem un programa per calcular la distribució del consum 
        elèctric al nostre centre i la disponibilitat d'espai per estudiant 
        a cada aula: 
     | 
  
   
    |   | 
      | 
  
   
      | 
     
      
         
          |  
             /** 
              * Càlcul de consum elèctric i espai de les aules de 
              l'institut 
              * 
              */  
               
              class CalculAules { 
               
                  public static void main(String args[]) { 
               
                      // 
              Creem un despatx 
                      Despatx d1 = new 
              Despatx("Oficina 1",40,false,600); 
                      d1.maquinadecafe=true; 
               
                      // 
              creem un laboratori 
                      Laboratori a1 = 
              new Laboratori("Laboratori 1", 
                                       75,true,1200,20); 
                      a1.bunsens = 12; 
               
                      // 
              creem una aula d'informàtica 
                      Informatica a2 = 
              new Informatica("Informàtica 1", 
                                        
75,true,6000,15); 
                      a2.impressores = 
              3; 
               
                      // 
              creem un gimnàs 
                      Gimnas a3 = new 
              Gimnas("Gimnàs",500,true,3000,200); 
                      a3.grades = 2000; 
               
                      // 
              Consum d'electricitat 
                      Espai[] espais = 
              {d1,a1,a2,a3}; 
                      System.out.println("Consum 
              elèctric"); 
                      System.out.println("---------------------------------"); 
                      double consumtotal=0; 
                          for 
              (int n=0; n<espais.length; n++) { 
                consumtotal+=espais[n].consumelectric; 
                System.out.println("L'espai
"+ 
                                  
espais[n].codi+" consumeix: "+ 
                                   espais[n].consumM2()+ 
                                  
" W/m2"); 
                          } 
                      System.out.println("El 
              consum total de l'institut és de: "+ 
                           consumtotal+ 
                          
" W\n\n");  
               
                      // 
              Càlcul de superfícies per estudiant  
                      Aula[] aules = {a1,a2,a3}; 
                      System.out.println("Superfície 
              per estudiant"); 
                      System.out.println("---------------------------------"); 
                          for 
              (int n=0; n<aules.length; n++) { 
                System.out.println("L'Aula
"+ 
                                  
aules[n].codi+ 
                                   "
disposa de: "+ 
                                   aules[n].espaiEstudiant()+ 
                                  "
m2 per estudiant"); 
                          } 
                  } 
              } 
           | 
         
       
     | 
  
   
    |   | 
      | 
  
   
    |   | 
     
       El càlcul de l'electricitat de les aules forma part de la superclasse 
        "Espai". Podem cridar el mètode 
        public double consumM2() des de qualsevol subclasse. 
        Les aules disposen d'un mètode 
        específic public double espaiEstudiant(), 
        que podem cridar des de qualsevol objecte 
        d'aquesta classe. Els objectes "Gimnas" 
        tenen lleugerament canviat el sistema de càlcul dels espais.  
      Segons el llenguatge d'objectes en el 
        programa hem utilitzat: 
      
        - Sobrecàrrega de 
          mètodes constructors i d'instància. 
          Totes les classes 
          disposen de dos constructors, 
          un amb paràmetres 
          i l'altre sense. Podem utilitzar els dos indistintament. El compilador 
          s'encarregarà de decidir quin dels dos ha d'utilitzar quan creem 
          un objecte de la classe. 
          Buscarà aquell mètode que s'adeqüi exactament a l'estructura 
          de paràmetres 
          que passem. Podem sobrecarregar els 
          mètodes tantes vegades com vulguem, 
          sempre que la distribució de 
          paràmetres sigui única i, si 
          es donen repeticions, el compilador ens donarà error. Una sobrecàrrega 
          com aquesta no seria correcta:
 
           
          
             
              class Aula 
                extends Espai { 
                 
                    public Aula(int metres) { 
                        ...  
                    } 
                 
                    //Repetim 
                constructor amb un únic paràmetre enter, 
                    //No es pot fer! 
                    public Aula(int places) {  
                        ...  
                    } 
                 
                } | 
             
           
           
          Hem utilitzat sobrecàrrega 
          de mètodes d'instància a la 
          classe Aula, 
          on permetem dues formes diferents de càlcul de la superfície 
          disponible per estudiant. 
           
           
        - Sobreescriptura de mètodes: 
          moltes vegades és interessant conservar el nom 
          i tipus de retorn 
          dels mètodes 
          a les subclasses, 
          però definint-ne un funcionament intern diferent. Nosaltres hem 
          aplicat aquest criteri a la classe Gimnas. 
          Els objectes 
          Gimnas disposen 
          d'un mètode 
          public double espaiEstudiant() 
          aparentment igual a la resta d'aules. El mecanisme de càlcul 
          del mètode, 
          però, no és el mateix. Com hem vist, la diferència 
          queda encapsulada 
          i es fa invisible per als programes que utilitzin les aules.
 
           
         
        - Hem cridat al constructor 
          de la superclasse amb l'expressió 
          super(). Si la superclasse 
          disposa de més d'un constructor, 
          com podem decidir quin d'ells cridarem a l'hora l'instanciar 
          les subclasses? super() ens permet 
          accedir als constructors de la superclasse 
          seguint un criteri similar a la sobrecàrrega 
          de mètodes: en funció dels paràmetres 
          que definim a super() s'activarà un 
          o altre constructor.
 
       
     | 
  
   
    |   | 
     
         
     | 
  
   
    |   | 
     
      
     | 
  
   
      | 
  
   
    |   | 
      | 
  
   
    |   | 
      |