Java  World     Capítulo  7     2  
  




Capítulo  8     Clases  internas                                                                                                                                     h
Una  clase  interna  básicamente  es  lo  que  el  nombre  indica,  una  clase  que  se  encuentra  dentro  de  otra  clase.  Existen  diferentes  tipos             t
de  ellas,  y  las  maneras  de  instanciar  las  mismas  también  es  diferente,  de  manera  que  las  veremos  una  a  una.                                       t
                                                                                                                                                                     p
Durante  el  capítulo  veremos  4  conceptos:                                                                                                                        :
          Clases  internas                                                                                                                                           /
              o Clases  internas  normales                                                                                                                           /
              o Clases  internas  de  método                                                                                                                         g
              o Clases  internas  anónimas                                                                                                                           u
          Clases  estáticas  anidadas                                                                                                                                s
Algunas  reglas  sobre  las  clases  internas:                                                                                                                       t
                                                                                                                                                                     a
          Tienen  acceso  a  todos  los  atributos  y  métodos  de  su  clase  contenedora,  por  más  que  los  mismos  sean  private.                              v
          Debe  de  existir  una  instancia  de  la  clase  contenedora  para  poder  crear  una  instancia  de  la  clase  interna,  sin  excepción.  
                                                                                                                                                                     o
          Las  clases  internas  siempre  mantienen  una  referencia  a  la  clase  contenedora.  
                                                                                                                                                                     a
          Al  igual  que  las  clases  normales,  no  es  posible  definirlas  como  abstract  y  final.  
                                                                                                                                                                     l
Clase  interna  normal                                                                                                                                               b
                                                                                                                                                                     e
     class  Externa  {                                                                                                                                               r
         class  Interna  {  
                                                                                                                                                                     o
         }  
     }                                                                                                                                                               l
  
                                                                                                                                                                     a
Primer  punto  a  tener  en  cuenta,  es  que  este  código  al  precompilarlo  genera  dos  clases:                                                                 .
                                                                                                                                                                     b
          Externa.class  
                                                                                                                                                                     l
          Externa$Interna.class  
                                                                                                                                                                     o
                                                                                                                                                                     g
                           Una  clase  interna  no  puede  tener  métodos  estáticos.                                                                                s
                                                                                                                                                                     p
                                                                                                                                                                     o
Instanciación                                                                                                                                                        t
                                                                                                                                                                     .
Desde  dentro  de  la  clase  externa,  la  clase  interna  es  visible,  de  manera  que  lo  siguiente  es  válido:  
  
                                                                                                                                                                     c
                                                                                                                                                                     o
     class  Externa  {                                                                                                                                               m  
         public  void  hazAlgo()  {  
             Interna  i  =  new  Interna();;  
         }  
       
         class  Interna  {  
         }  
     }  
A  su  vez,  la  clase  interna  tiene  conocimiento  de  la  clase  externa,  pudiendo  acceder  a  sus  métodos  y  atributos  como  propios.  
                                             




  
3          Java  World     Capítulo  7  
              




            Instanciación  fuera  de  la  clase  
h
t                                                                                                                                                       tiene  que  haber  
t           primero  una  instancia  de  la  clase  externa  para  que  pueda  existir  una  instancia  de  la  clase  interna   
            Bien,  según  el  código  anterior,  la  instanciación  de  ambas  clases  desde  fuera  de  la  clase  sería:  
p
:
                  Externa  externa  =  new  Externa();;  
/                 Externa.Interna  interna  =  externa.new  Interna();;  
/             
v
a           Referenciando  a  la  clase  externa  desde  la  interna  
l           Dado  que  el  modificador   this  se  encuentra  reservado  para  el  objeto  que  llamó  el  método  actual  en  ejecución,  no  nos  sirve  para  
o           invocar  otra  instancia.  Para  poder  referenciar  a  instancia  de  la  clase  externa  dentro  de  la  interna  la  sintaxis  sería:  
                      [NombreClaseExterna].this  
r
c
r                class  Externa  {  
                     class  Interna  {  
e
                         public  void  hazAlgo()  {  
a                            Externa  externa  =  Externa.this;;  //Referencia  de  la  clase  contenedora  
t                            Interna  interna  =  this;;                  //Referencia  de  la  propia  clase  interna  
                         }  
i                    }  
v                }  
                   
o
.           Modificadores  aplicables  
b           Los  modificadores  de  acceso  que  se  pueden  aplicar  a  la  clase  interna  normal  son:  
l
                         final  
o                        abstract  
g                        public  
s                        private  
p                        protected  
o                        static  (transforma  la  clase  en  una  clase  común.  Lo  veremos  más  adelante)  
t                        strictfp  

.           Clase  interna  de  método  local  
c           Es  posible  declarar  una  clase  interna  dentro  de  un  método.  
o
m                class  Externa  {  
                     public  void  hazAlgo()  {  
                         class  Interna  {  
                             public  void  hazOtraCosa()  {}  
                         }  
                     }  
                 }  


                                          
                                        El  que  hayas  declarado  una  clase  de  método  local  no  significa  que  hayas  creado  una  instancia  de  esta  clase.  
                                          

              
            De  manera  que  si  quisieramos  crear  una  instancia  de  Interna,  esto  solo  podría  realizarse  dentro  del  método  hazAlgo().  
              

              
Java  World     Capítulo  7        4  
  




Cosas  que  se  pueden  y  no  hacer  dentro  de  una  clase  interna  de  método                                                                                          h
                                                                                                                                                                           t
           No  se  puede  acceder  a  las  variables  definidas  dentro  del  método,  salvo  que  estas  se  definan  como  final.  
           Puede  acceder  a  los  atributos  de  la  clase  externa.  
                                                                                                                                                                           t
                  o Solo  podrá  acceder  a  atributos  estáticos,  si  es  que  fue  declarada  como  static  (no  existe  el  this).                                     p
           La   clase   puede   declararse   dentro   del   método,   pero   la   referencia   puede   almacenarse   en   otra   referencia,   de   manrea   que           :
           finalizado  el  método  el  objeto  siga  existiendo.                                                                                                           /
                                                                                                                                                                           /
Modificadores  aplicables  
                                                                                                                                                                           g
Los  modificadores  de  acceso  que  se  pueden  aplicar  a  una  clase  interna  de  método  local  son:                                                                  u
           abstract                                                                                                                                                        s
           final                                                                                                                                                           t
Clases  internas  anónimas                                                                                                                                                 a
                                                                                                                                                                           v
Estas  conforman  las  porciones  de  código  más  extrañas  que  podamos  encontrar  en  Java.  Veamos  un  ejemplo  primero:  
                                                                                                                                                                           o
                                                                                                                                                                           a
     class  ClaseDos  {  
         public  void  hazAlgo()  {}                                                                                                                                       l
     }                                                                                                                                                                     b
       
     class  Original  {                                                                                                                                                    e
         ClaseDos  c  =  new  ClaseDos()  {                                                                                                                                r
             public  void  hazAlgo()  {                                                                                                                                    o
                 System.out.println("Método  pop  sobrescrito");;  
             }                                                                                                                                                             l
         };;                                                                                                                                                               a
     }  
                                                                                                                                                                           .
                                                                                                                                                                           b
                            
                                                                                                                                                                           l
                          La  declaración  de  una  clase  anónima  debe  cerrar  la  última  llave  con  un  ;  (punto  y  coma),  salvo  que  se  este  
                          definiendo  como  parámetro  de  un  método.                                                                                                     o
                                                                                                                                                                           g
  
                                                                                                                                                                           s
El  concepto  de  anónima  viene  porque  se  está  sobreescribiendo  una  clase  (o  interfaz),  pero  no  se  está  definiendo  un  nuevo  tipo.  
  
                                                                                                                                                                           p
Conceptos  a  tener  en  cuenta  de  la  clase  anónima:                                                                                                                   o
                                                                                                                                                                           t
           La   clase   anónima   puede   extender   de   una   clase   normal,      abstract   o   implementar   una   interface,   pero   solo   puede  
                                                                                                                                                                           .
           extender/implementar  de  una  de  las  anteriores  mencionadas  (no  puede  extender  de  a  e  implementar  la  interfaz  b).  
           Desde  fuera  de  la  clase  anónima  solo  se  pueden  invocar  los  métodos  definidos  en  la  super  clase  o  interfaz.                                    c
           Se  pueden  crear  nuevos  métodos,  pero  estos  solo  pueden  ser  invocados  desde  otro  método  de  la  clase  anónima.                                    o
           También  es  posible  crear  una  clase  anónima  como  parámetro  de  una  función.                                                                            m  
        
                                            




  
5          Java  World     Capítulo  7  
              




            Veamos  un  ejemplo  de  una  clase  anónima  declarada  como  parámetro  de  un  método,  que  a  su  vez  extiende  de  una  clase  abstract.  
h
t                 class  Perro  {  
                      public  void  perseguir(Gato  g)  {    
t                         System.out.println("El  perro  comienza  a  perseguir  al  gato");;  
p                         g.huir();;  
                      }  
:
                  }  
/                   
/                 abstract  class  Gato  {  
                      abstract  public  void  huir();;  
v                 }  
a                   
                  class  Duenio  {  
l                     public  void  hazAlgo()  {  
o                         Perro  p  =  new  Perro();;  
r                         p.persegir(new  Gato()  {  
                              public  void  huir()  {  
c                                 System.out.println("El  gato  logró  huir  exitosamente");;  
r                             }  
                          });;  
e                     }  
a                 }                                                                                                                                               
t
i                                        
                                       El  perro  comienza  a  perseguir  al  gato  
v
                                       El  gato  logró  huir  exitosamente  
o
.             
b
            Crear  una  clase  anónima  a  partir  de  una  interfaz  
l
            Una  clase  anónima  puede  implementar  una  interfaz,  pero  la  declaración  de  la  misma  no  es  como  se  hace  normalmente.  Veamos  un  
o
            ejemplo:  
g
s                interface  Animal  {  
p                    public  void  emitirSonido();;  
                 }  
o                  
t                class  Familia  {  
                     Animal  mascota  =  new  Animal()  {  
.                        public  void  emitirSonido()  {  
c                            System.out.println("wof  wof!");;  
o                        }  
                     };;  
m                    mascota.emitirSonido();;  
                 }  
                   
              

                                        
                                      wof  wof!  


              
            Como  podemos  apreciar,  se  utiliza  tanto  clases  como  interfaces  de  la  misma  manera  en  cuanto  a  clases  anónimas  se  refiere.  
            new  [Class  o  Interface]()  {}  
                                                      



              
Java  World     Capítulo  7          6  
  




Clases  estáticas  anidadas                                                                                                                                                        h
Una  clase  estática  anidada  es  simplemente  una  clase  definida  como  un  atributo  estático  de  la  clase  padre.                                                          t
                                                                                                                                                                                   t
Conceptos  que  cambian  con  respecto  a  las  clases  internas:                                                                                                                  p
          No  requieren  de  una  clase  externa  para  poder  crear  una  instancia  de  la  interna.                                                                             :
          No  pueden  acceder  a  atributos  y  métodos  de  la  clase  externa  que  no  estén  definidos  como  static.                                                          /
          Se  comporta  como  una  clase  normal,  solo  que  la  ruta  de  acceso  es  a  través  de  ClaseExterna.ClaseInterna.                                                  /
               o Salvo   en   el   caso   que   estemos   en   un   método   de   la   clase   externa,   en   el   cual   la   clase   interna   puede   ser   accedida           g
                   directamente  como  ClaseInterna.  
                                                                                                                                                                                   u
                                                                                                                                                                                   s
   class  Persona  {  
       static  class  Personita  {                                                                                                                                                 t
           public  void  hazAlgo()  {                                                                                                                                              a
               System.out.println("Personita  hace  algo");;  
           }  
                                                                                                                                                                                   v
       }                                                                                                                                                                           o
   }                                                                                                                                                                               a
     
   public  class  General  {                                                                                                                                                       l
                                                                                                                                                                                   b
       static  class  Cabo  {  
           public  void  hazAlgo()  {                                                                                                                                              e
               System.out.println("Cabo  hace  algo");;                                                                                                                            r
           }  
       }  
                                                                                                                                                                                   o
       //  Tener  en  cuenta  que  el  método  main  está  definido  dentro  de  General                                                                                           l
       static  public  void  main(String[]  args)  {                                                                                                                               a
           Persona.Personita  p  =  new  Persona.Personita();;  
           Cabo  c  =  new  Cabo();;                                                                                                                                               .
           p.hazAlgo();;  //  Personita  hace  algo                                                                                                                                b
           c.hazAlgo();;  //  Cabo  hace  algo  
       }                                                                                                                                                                           l
   }                                                                                                                                                                               o
                                                                                                                                                                                   g
                                                                                                                                                                                   s
                                                                                                                                                                                   p
Capítulo  9     Hilos  de  ejecución  (Threads)                                                                                                                                    o
Un  hilo  de  ejecución  es  un  proceso  liviano  desencadenado  por  otro  proceso,  y  dependiente  de  este  último.  El  nuevo  hilo  tendrá  un                              t
stack  aparte.                                                                                                                                                                     .
En  palabras  más  simples,  un  hilo  de  ejecución  es  un  proceso  paralelo  con  respecto  al  proceso  principal,  lo  que  lleva  a  cabo  que  en                          c
computadoras  con  más  de  un  nucleo  (o  emulados),  haya  varios  procesos  ejecutando  nuestro  código  al  mismo  tiempo.                                                    o
  
                                                                                                                                                                                   m  
Que  representa  para  Java  un  Thread?  

          Una  clase  java.lang.Thread  
          Un  hilo  de  ejecución  

Para  el  examen  es  necesario  conocer  cuando  una  sintaxis  está  creando  código  multithread  seguro  y  cuando  no.  
                                              




  
7          Java  World     Capítulo  7  
              




            Creando  un  thread  
h
t           Dentro  de  la  clase  java.lang.Thread  se  encuentran  una  serie  de  métodos.  Dentro  de  estos  deberás  de  conocer  los  siguientes:  
t
                         start()  
p                        yield()  
:                        sleep()  
/                        run()  
/
            Para  poder  crear  un  nuevo  Thread  debes  de  cumplir  el  contrato  de  la  interfaz  java.lang.Runnable,  el  cual  tiene  un  solo  método:  
v
            public  void  run();  
a           Para  ello,  la  clase  que  utilicemos  tiene  que  implementar  dicha  interfaz,  o  extender  la  clase  java.lang.Thread.  
l
o           Definiendo  un  Thread  extendiendo  Thread  
r
c                class  MiClaseThread  extends  Thread  {  
r                    public  void  run()  {  
                         System.out.println("Oh,  JavaWorld  esta  en  un  Thread!");;  
e                    }  
a                }  
                   
t             
i
            Definiendo  un  Thread  implementando  Runnable  
v
o
                 class  MiClaseRunnable  implements  Runnable  {  
.                    public  void  run()  {  
b                        System.out.println("Oh,  JavaWorld  esta  en  un  Thread!");;  
                     }  
l                }  
o                  
              
g
            Instanciando  un  Thread  
s
p           Si  o  si  es  necesaria  una  instancia  de  Thread  para  poder  correr  un  hilo  de  ejecución.  
o           Para  eso  tenemos  dos  posibilidades,  dependiendo  de  si  extendimos  de  Thread,  o  implementamos  Runnable.  

t           Instanciando  un  Thread  que  extiende  de  Thread  
.
c                Thread  hilo  =  new  miClaseConThread();;  
o           Creamos  un  objeto  MiClaseConThread  y  lo  asignamos  a  una  referencia  de  tipo  Thread,  dado  que  extiende  de  Thread,  la  relación  Is-­‐A  
m           Thread  es  legal.  

            Instanciando  un  Thread  que  implementa  Runnable  

              Runnable  hiloRunnable  =  new  miClaseConThread();;  
              Thread  hilo  =  new  Thread(hiloRunnable);;  
              //  O  la  versión  abreviada  
              Thread  hilo  =  new  Thread(new  miClaseConThread());;  
            En  este  caso,  lo   que  hacemos  es  primero  crear  una   instancia  de  nuestra  clase  y  almacenarla   en  una   referencia  de  tipo  Runnable.  
            Luego,  utilizamos  uno  de  los  constructores  sobrecargados  de  Thread,  el  cual  recibe  un  objeto  de  tipo  Runnable.  
                                                       




              
Java  World     Capítulo  7         8  
  




La  clase  Thread                                                                                                                                                                  h
Como  mencionamos  anteriormente,  Thread  tiene  una  serie  de  constructores  sobrecargados:                                                                                    t
                                                                                                                                                                                   t
            Thread()  
                                                                                                                                                                                   p
            Thread(Runnable  objetivo)  
                                                                                                                                                                                   :
            Thread(Runnable  objetivo,  String  nombre)  
            Thread(String  nombre)  
                                                                                                                                                                                   /
                                                                                                                                                                                   /
Si   probamos   los   códigos   anteriores   en   una   aplicación   en   Java,   notaríamos   que   no   pasa   nada.   La   cuestión   es   que   el   instanciar   un           g
Thread   no   hace   que   se   lance   el   hilo   de   ejecución   del   mismo,   de   manera   que   no   se   ejecuta.   Para   poder   determinar   en   que  
                                                                                                                                                                                   u
condiciones  de  ejecución  se  encuentra  el  Thread  lo  podemos  clasificar  en  tres  estados:  
                                                                                                                                                                                   s
Estado             Descripción                                                                                                                                                     t
new                Cuando  un  Thread  ha  sido  instanciado  (invocación  del  new)  se  encuentra  en  estado  nuevo.                                                            a
(nuevo)                                                                                                                                                                            v
alive              Cuando  el  hilo  de  ejecución  es  lanzado  (se  crea  un  nuevo  stack  para  el  hilo  y  se  ejecuta  el  contenido  de  run()  ),  se  dice               o
(vivo)             que  el  Thread  está  vivo.                                                                                                                                    a
dead               Cuando  el  hilo  de  ejecución  completa  el  método  run,  se  dice  que  el  Thread  está  muerto.                                                           l
(muerto)                                                                                                                                                                           b
Iniciando  la  ejecución  de  un  Thread                                                                                                                                           e
Simplemente,  para  iniciar  la  ejecución  de  un  nuevo  Thread,  se  utiliza  el  método  start().                                                                              r
                                                                                                                                                                                   o
     Runnable  hiloRunnable  =  new  miClaseConThread();;  
     Thread  hilo  =  new  Thread(hiloRunnable);;                                                                                                                                  l
     hilo.start();;                                                                                                                                                                a
                                                                                                                                                                                   .
Tambien   hay   que   tener   mucho   cuidado   con   la   llamada   a   run().   Cuando   invocamos   el   método   start(),   este   primero   crea   un   nuevo                 b
stack,  y  luego  lanza  el  método  run()  como  miembro  inicial  de  dicho  stack  en  un  hilo  de  ejecución  aparte.    
                                                                                                                                                                                   l
                                                                                                                                                                                   o
                            Si  se  invoca  directamente  el  método  run()  no  generará  un  error,  pero  el  mismo  no  se  ejecutará  en  un  nuevo                           g
                            thread,  sino  que  sería  como  llamar  a  un  método  normal.                                                                                        s
                                                                                                                                                                                   p
                                               
                                                                                                                                                                                   o
                                                                                                                                                                                   t
                                                                                                                                                                                   .
                                                                                                                                                                                   c
                                                                                                                                                                                   o
                                                                                                                                                                                   m  




  
9          Java  World     Capítulo  7  
              




            Ejecutando  Threads  
h
t           Vamos  a  lo  que  nos  concierne,  corramos  algunos  hilos:  
t              class  PruebasRunnable  implements  Runnable  {  
p                  private  int  iteraciones  =  4;;  
:                        
                   public  void  run()  {  
/                      for  (int  x  =  0  ;;  x  <  iteraciones;;  x++  )  {  
/                          System.out.println("Ejecutando  ["  +  Thread.currentThread().getName()  +  "]  ["  +  x  
                                                                   +  "]");;  
v                      }  
a                  }  
l                    
                   static  public  void  main(String[]  args)  {  
o                      Runnable  hilo  =  new  PruebasRunnable();;  
r                        
                       Thread  hilo1  =  new  Thread(hilo,  "Hilo  1");;  
c                      Thread  hilo2  =  new  Thread(hilo,  "Hilo  2");;  
r                      Thread  hilo3  =  new  Thread(hilo,  "Hilo  3");;  
                         
e                      hilo1.start();;  
a                      hilo2.start();;  
                       hilo3.start();;  
t
                   }  
i              }  
v                
o                                      Ejecutando  [Hilo  1]  [0]  
.                                      Ejecutando  [Hilo  2]  [0]  
b                                      Ejecutando  [Hilo  3]  [0]  
                                       Ejecutando  [Hilo  2]  [1]  
l                                      Ejecutando  [Hilo  1]  [1]  
o                                      Ejecutando  [Hilo  2]  [2]  
g                                      Ejecutando  [Hilo  3]  [1]  
s                                      Ejecutando  [Hilo  2]  [3]  
                                       Ejecutando  [Hilo  1]  [2]  
p
                                       Ejecutando  [Hilo  3]  [2]  
o                                      Ejecutando  [Hilo  1]  [3]  
t                                      Ejecutando  [Hilo  3]  [3]  
.                                        
c
                                           
o                                        El  orden  de  ejecución  de  los  hilos  no  puede  ser  jamás  predecido.  
m  

              
            Por  más  que  conozcamos  el  orden  en  que  son  inicializados,  ni  siquiera  esto  nos  asegura  de  que  el  orden  de  ejecución  de  los  mismos  
            sea  ese.  
            El  sistema  de  hilos  y  tareas  es  manejado  por  el  Sistema  Operativo  en  conjunto  con  la  JVM,  son  ellos  quienes  asignarán  el  proceso  y  
            otorgaran  los  tiempos  que  el  mismo  se  encuentra  en  ejecución.  
            Otra  cuestión  a  tener  en  cuenta  es  que  un  Thread  solo  puede  ser  llamado  una  única  vez  en  toda  su  existencia.  

                                           
                                         El   llamar   al   método   start()   más   de   una   vez   desde   el   mismo   Thread   generará   el   lanzamiento   de   una  
                                         excepción  IllegalThreadStateException.  

              


              
Java  World     Capítulo  7         10  
  




Estados  y  transiciones  de  los  threads                                                                                                                                        h
En  total  podemos  contar  5  estados  en  los  cuales  puede  estar  un  thread.  Veamos  un  gráfico  de  esto  para  entender  un  poco  mejor:                               t
                                                                                                                                                                                  t
                                     Alive  (vivo)                                                                                                                                p
                                                                          Waiting                                                                                                 :
                                                                         /Blocking                                                                                                /
               New                                                      (esperando                                                       Dead                                     /
             (nuevo)                                                   /bloqueado)                                                     (muerto)                                   g
                                                                                                                                                                                  u
                                                                                                                                                                                  s
                                                                                                                                                                                  t
                                             Runnable                                                  Running                                                                    a
                                            (esperando                                                    (en  
                                                                                                                                                                                  v
                                             ejecución)                                               ejecución)  
                                                                                                                                                                                  o
                                                                                                                                                                                  a
                                                                                                                                                                                  l
                                                                                                                                                                                  b
                                                                                                                                                                                  e
Tabla  de  estados  
Estado                             Descripción                                                                                                                                    r
New                                Este  estado  se  da  cuando  se  ha  invocado  al  new  del  Thread,  pero  aun  no  se  ha  llamado  al  método                              o
(nuevo)                            start().                                                                                                                                       l
Runnable                           Este  estado  se  da  cuando  el  thread  se  encuentra  listo  para  ser  ejecutado,  y  está  esperando  que  el                             a
(esperando  ejecución)             gestionador  de  eventos  de  la  JVM  lo  seleccione  para  comenzar  la  ejecución.                                                          .
Running                            Este  estado  se  da  cuando  el  thread  fue  seleccionado  por  el  gestionador  de  eventos  y  se  encuentra                               b
(en  ejecución)                    actualmente  en  ejecución.  
                                                                                                                                                                                  l
Waiting/Block                      Este  estado  se  da  cuando  el  thread  requiere  algún  recurso  (I/O  por  ejemplo),  de  manera  que  para  
(esperando/bloqueado)              no  consumir  recursos  de  CPU  queda  esperando.  También  puede  pasar  que  se  le  haya  ordenado  que  
                                                                                                                                                                                  o
                                   se  durmiera,  de  manera  que  despertará  cuando  acabe  el  tiempo  (si  se  especificó),  o  que  otro  thread                             g
                                   le  envíe  una  señal  para  despertarlo.                                                                                                      s
Dead                               Este   estado   se   da   cuando   el   thread   completó   la   ejecución   del   método   run.   Aun   sigue   siendo   un                   p
(muerto)                           objeto,  el  cual  solicito  que  se  liberarn  sus  recursos.                                                                                 o
Durmiendo  (Sleep)                                                                                                                                                                t
Sleep  es  un  método  estático  de  la  clase  Thread.  Este  solo  puede  afectar  al  Thread  que  actualmente  se  está  ejecutando,  de  manera                              .
que  un  Thread  no  puede  dormir  a  otro.                                                                                                                                      c
Cuando  un  Thread                                                                                                                                                                o
Los  métodos  sleep  son:  
                                                                                                                                                                                  m  
          sleep()  
          sleep(long  milisegundos)  

                                                                                                                                    
El  segundo  lo  duerme  por  un  tiempo  determinado.  

                             Cuando   se   especifica   un   tiempo   de   sleep,   este   representa   el   tiempo   mínimo   que   el   thread   permanecerá  
                             dormido,  pero  no  es  el  tiempo  exacto.  

  


  
11          Java  World     Capítulo  7  
           




         Además,  este  método  puede  generar  una  excepción  InterruptedException,  por  lo  que  hay  que  llamarlo  dentro  de  un  Try-­‐Catch.  
h        Hagamos  un  ejemplo  simple:  
t
t
               import  java.lang.InterruptedException;;  
p
                 
:              public  class  PruebasRunnable01  implements  Runnable  {  
/                  static  public  void  main(String[]  args)  {  
                       (new  Thread(new  PruebasRunnable01())).start();;  
/                  }  
v                    
                   public  void  run()  {  
a                      for  (int  x  =  1  ;;  x  <=  101  ;;  x  ++)  {  
l                          if  (x%10  ==  0)  {  
                               System.out.println("Running  "  +  x);;  
o
                           }  
r                          try  {  
c                              Thread.sleep(500);;  //  1  milisegundo  *  500  =  1/2  segundo  
                           }  catch(InterruptedException  ex)  {}  
r                      }  
e                  }  
               }  
a
           
t
i        Yield()  y  threads  con  prioridades  
v        Los  threads  siempre  se  ejecutan  con  una  prioridad,  generalmente,  esta  se  representa  con  un  número  del  1  al  10.  
o                                                                                                                                                                        Si  el  
.        thread   excede   el   tiempo,   se   pausa   su   ejecución,   y   se   devuelve   a   la  
b        thread  para  que  se  ejecute.  Otras  utilizan  una  lógica  que  permiten  a  un  thread  ejecutarse  hasta  la  finalización  del  método  run.  
l
                                                                                    
o
           
g
s                                     La  JVM  no  especifica  que  las  prioridades  se  sigan  al  pie  de  la  letra,  de  manera  que  solo  utilizamos  estas  para  
p                                     optimizar  el  código,  pero  no  dependan  de  ellas  para  determinar  la  lógica  del  programa.  
o
t          
.        Esto  nos  deja  con  dos  posibles  comportamientos:  

c                                                                                                                          mplete  o  se  bloque.  
o                     Se  utilizan  tiempos  máximos  de  ejecución,  de  manera  que  todos  los  threads  (o  la  gran  mayoría),  tengan  una  oportunidad  de  
m                     ejecutarse.  

         Estableciendo  la  prioridad  de  los  threads  
         El  thread  recibe  una   prioridad  por  defecto,  la  cual  corresponde  a   la   prioridad  del  thread  con  que  fue  creado.  Esta   comprende  un  
         rango  que  va  generalmente  del  1  al  10,  pero  no  todas  las  JVM´s  contienen  este  rango.  
         Por  defecto,  los  threads  main  son  creados  con  prioridad  5.  
         Existen  también  algunos  identificadores  en  la  clase  Thread  para  indicar  las  prioridades:  

                      Thread.MIN_PRIORITY                      1  
                      Thread.NORM_PRIORITY                     5  
                      Thread.MAX_PRIORITY                      10  

         La   prioridad   se   establece   mediante   el   método   setPriority(int   prioridad).   Este   es   un   método   de   instancia   perteneciente   a   la   clase  
         Thread.  

           
Java  World     Capítulo  7         12  
  




Ejemplo:  
                                                                                                                                                                                  h
  Thread  t  =  new  MiThread();;                                                                                                                                                 t
  t.setPriority(Thread.MAX_PRIORITY);;                                                                                                                                            t
  t.start();;  
                                                                                                                                                                                  p
La  JVM  nunca  cambiará  la  prioridad  de  un  thread.  
                                                                                                                                                                                  :
El  método  yield()  
                                                                                                                                                                                  /
Este  método  lo  que  hace  es  enviar  una  sugerencia  
                                                                                                                                                                                  /
hay  que  tener  en  cuenta  que  esto  es  una  sugerencia,  y  puede  que  nunca  se  cumpla.  También  puede  que  se  cumpla,  pero  al  enviar  el  
                                                                                                                          
                                                                                                                                                                                  g
                                                                                                                                                                                  u
Thread.                                                                                                                                                                           s
                                                                                                                                                                                  t
El  método  join()  
                                                                                                                                                                                  a
Este  método  permite  unir  la  ejecución  de  un  thread  al  final  de  la  otra.  Supongamos  que  tenemos  dos  threads  A  y  B.  A  requiere  que  B  
                                                                                                                                                                                  v
se  ejecute  para  poder  continuar,  de  manera  que  A  realiza  un  join  contra  B.  Cuando  B  termine  su  ejecución,  recién  en  ese  momento  A  
                                                                                                                                                                                  o
                                                                                                
Este  es  un  método  de  instancia  perteneciente  a  la  clase  Thread.                                                                                                         a
                                                                                                                                                                                  l
Sincronización  de  código                                                                                                                                                        b
La  sincronización  es  el  termino  utilizado  para  que  varios  elementos  que  utilizan  un  recurso  compartido  no  generen  inconsistencia  de                             e
datos.                                                                                                                                                                            r
En  el  siguiente  ejemplo  de  código  pueden  ver  un  caso  en  particular  con  una  cuenta  bancaria.  Ejecutenlo  varias  veces  y  verán  como  a  
                                                                                                                                                                                  o
veces  el  saldo  queda  en  negativo  y  otras  no.  
  
                                                                                                                                                                                  l
Para  ver  el  ejemplo,  dirígete  al  enlace  y  compila  el  código.                                                                                                            a
                                                                                                                                                                                  .
Lo  que  debemos  hacer   en  orden  de  preserva                                                                                                                                 b
atómica   (en   realidad   el   término   no   es   del   todo   correcto,   dado   que   una   operación   atómica   es   aquella   que   solo   contiene   una                  l
instrucción.  En  este  caso,  se  utiliza  para  identificar  un  conjunto  de  instrucciones  que  deben  de  procesarse  como  una  sola).                                     o
Para   ello   podemos   utilizar   el   modificador   synchronized.   Este   lo   que   hace   es   asegurarse   de   que   solo   un   objeto   por   vez   pueda  
                                                                                                                                                                                  g
acceder  al  recurso  (en  este  caso  el  método),  pero  no  asegura  que  el  objeto  ejecute  en  una  pasada  todo  el  código.    
Si   un   objeto   ejecuta   el   código   y   se   interrumpe   dentro   del   mismo,   se   mantiene   una   llave,   de   manera   que   otro   objeto   no   pueda            s
acceder  hasta  que  el  que  estaba  bloqueado,  vuelva  y  termine  con  la  ejecución.                                                                                         p
                                                                                                                                                                                  o
Veamos  el  mismo  ejemplo  pero  ahora  sincronizado.  Ejecutenlo  las  veces  que  quieran.  Verán  que  el  saldo  de  la  cuenta  jamás  será                                 t
negativo.                                                                                                                                                                         .
  
                                                                                                                                                                                  c
Para  ver  el  ejemplo,  dirígete  al  enlace  y  compila  el  código.  
                                                                                                                                                                                  o
                                              
                                                                                                                                                                                  m  




  
13          Java  World     Capítulo  7  
           




         Sincronización  y  bloqueos  
h
t        La   sincronización   funciona   mediante   bloqueos.   Denominamos   bloqueo   al   método   que   implementa   synchronized,   y   monitor   al  
t        objeto  que  accede  al  bloqueo.  
         Puntos  clave  sobre  synchronized:  
p
:                     Solo  se  pueden  sincronizar  métodos  o  bloques  de  código.  
/                     Cada  objeto  solo  tiene  un  bloqueo.  
/                     No  es  necesario  sincronizar  todos  los  métodos  de  una  clase.  
v                     Solo  puede  acceder  un  monitor  al  bloqueo  por  vez.  
a                     Si   se   utiliza   la   sincronización   en   forma   incorrecta,   se   pueden   llegar   a   generar   deadlocks   (bloqueos   de   la   muerte).   Esto  
                      sucede  cuando  dos  objetos,  contienen  un  bloqueo,  y  ambos  requieren  acceder  al  bloqueo  del  contrario.  
l
                                                                                                                                                                   tor).  
o
                      Un  thread  puede  adquirir  más  de  un  bloqueo.  
r                     Es  posible  sincronizar  un  bloque  de  código  en  vez  de  un  método  completo.  
c
r          
e             //Método  de  instancia  sincronizado  
a             public  synchronized  hazAlgo()  {  
                  System.out.println("Codigo  sincronizado");;  
t             }  
i             //Bloque  de  código  de  instancia  sincronizado  
              public  void  hazAlgo()  {  
v                 synchronized(this)  {  
o                     System.out.println("Codigo  sincronizado");;  
.                 }  
              }  
b             //Método  de  clase  sincronizado  
l             static  public  synchronized  hazAlgo()  {  
                  System.out.println("Static  -­  Codigo  sincronizado");;  
o             }  
g             //Bloque  de  código  de  clase  sincronizado  
              static  public  hazAlgo()  {  
s                 synchronized(MyClase.class)  {  
p                     System.out.println("Static  -­  Codigo  sincronizado");;  
o                 }  
              }  
t
                                                         
.
c
o
m  




           
Java  World     Capítulo  7         14  
  




Que  pasa  si  un  thread  no  obtiene  el  bloqueo?                                                                                                                            h
Si  un  objeto  intenta  acceder  a  por  ejemplo  un  método  sincronizado,  y  este  ya  está  bloqueado,  el  objeto  en  cuestión  queda  en  una                           t
lista  de  espera  especial  para  cuando  el  bloqueo  sea  liberado.                                                                                                          t
No  hay  una  lógica  que  indique  en  que  orden  se  obtiene  el  próximo  objeto  que  se  encuentra  en  la  lista  esperando  el  bloqueo.                                p
Cuadro  de  cómo  afectan  los  métodos  de  threads  a  los  bloqueos  
                                                                                                                                                                                :
Libera  el  bloqueo                                Mantiene  el  bloqueo                            Clase  que  contiene  el  método  
                                                                                                                                                                                /
wait()                                                notify()                                              java.lang.Object  
                                                      join()                                                java.lang.Thread  
                                                                                                                                                                                /
                                                      sleep()                                               java.lang.Thread                                                    g
                                                      yield()                                               java.lang.Thread                                                    u
Cuando  es  necesario  sincronizar?                                                                                                                                             s
Generalmente,  siempre  que  utilicemos  threads  será  necesario  que  hagamos  uso  de  la  sincronización,  siempre  que  tanto  en  métodos                                 t
estáticos  como  no  estáticos,  haya  datos  que  puedan  sufrir  modificaciones  y  que  no  sean  de  tipo  local,  se  deberán  de  marcar  como                            a
synchronized.                                                                                                                                                                   v
Hay  un  pequeño  tema,  dijimos  que  cada  clase  tiene  un  bloqueo  disponible,  pero  es  uno  para  la  clase  y  uno  para  la  instancia  (static                       o
y  no  static).  El  problema  es  que  si  un  método  de  clase  llama  a  un  atributo  estático,  y  el  primero  está  sincronizado,  solo  se  toma  un                   a
bloqueo,  el  de  la  clase.  Y  si  otro  objeto  llama  al  método  estático,  y  este  llama  al  atributo  de  clase,  solo  se  toma  el  bloqueo  estático.  Y  
                                                                                                                                                                                l
con  esto  ambos  objetos  pudieron  saltear  los  bloqueos  del  otro.    
De  más  está  decir  que  esta  situación  debes  evitarla  siempre  que  sea  posible  de  manera  que:  
                                                                                                                                                                                b
                                                                                                                                                                                e
           Los  atributos  estáticos  solo  se  deben  invocar  desde  métodos  estáticos  sincronizados.                                                                       r
           Los  atributos  de  clase  solo  se  deben  invocar  desde  métodos  de  clase  sincronizados.                                                                       o
                                                                                                                                                                                l
Clases  multi-­‐hilo  seguro  
                                                                                                                                                                                a
Cuando   una   clase   contiene   métodos   synchronized   cuidadosamente   colocados,   se   denomina   que   la   clase   es   multi-­‐hilo   seguro  
                                                                                                                                                                                .
(Thread-­‐Safe).   Pero   hay   un   problema,   que   la   clase   sea   thead-­‐safe   no   quita   que   podamos   implementarla   de   manera   incorrecta,  
produciendo  posibles  corrupciones  de  datos.  
                                                                                                                                                                                b
De  manera  que  cuando  utilicemos  threads,  debemos  depender  de  la  clase  que  llevaría  a  cabo  la  operación  atómica.                                                l
                                                                                                                                                                                o
Bloqueos  de  la  muerte  
                                                                                                                                                                                g
Esto  se  produce  cuando  dos  bloqueos  esperan  que  se  libere  el  bloqueo  del  contrario  para  poder  continuar.  Esto  generalmente  es  un                            s
error  muy  difícil  de  detectar,  además  de  que  cuando  trabajamos  con  threads,  el  reproducir  el  error  es  aun  más  complicado.  
                                                                                                                                                                                p
Interacción  entre  threads                                                                                                                                                     o
Para  comunicarse  entre  si,  se  utilizan  los  método:  wait(),  notify()  y  notifyAll().                                                                                   t
                                                                                                                                                                                .
                                                                                                                                                                                c
                           wait(),  notify(),  notifyAll()  solo  pueden  ser  invocados  desde  un  contexto  sincronizado.  Un  objeto  no  puede                             o
                           ionvocar  dichos  métodos  a  menos  que  posea  el  bloqueo.  
                                                                                                                                                                                m  
  
Los  métodos  wait()  y  notify()  pertenecen  a  la  clase  Object.  
Un  objeto  puede  tener  una  lista  con  0  ..  *  (0  a   muchos)  objetos  esperando  que  se  les  notifique  cuando  la  ejecución  de  este  haya  
terminado,  o  el  bloqueo  se  haya  liberado.  Veamos  un  ejemplo:  




  
15          Java  World     Capítulo  7  
           




           
h
t             //Compilación:              javac  -­g  PruebasRunnable04.java  
              //Ejecución:                java  PruebasRunnable04  
t               
p             public  class  PruebasRunnable04  {  
                  static  public  void  main(String[]  args)  {  
:
                      (new  PruebasRunnable04(new  Object())).pruebaWait();;  
/                 }  
/                   
                  private  Object  bloqueador;;  
v                   
a                 public  PruebasRunnable04(Object  bloqueador)  {  
                      this.bloqueador  =  bloqueador;;  
l                 }  
o                   
r                 public  void  pruebaWait()  {  
                      Incrementador  incrementador  =  new  Incrementador(bloqueador);;  
c                     (new  Thread(incrementador)).start();;  
r               
                      synchronized(bloqueador)  {  
e                         try  {  
a                             System.out.println("Esperando  a  que  se  complete  el  incrementador...");;  
                              bloqueador.wait();;  
t                         }  catch(InterruptedException  ex)  {}  
i                         System.out.println("El  total  es:  "  +  incrementador.getTotal());;  
v                     }  
                  }  
o                   
.             }  
              class  Incrementador  implements  Runnable  {  
b                 private  int  contador  =  0;;  
l                 private  Object  bloqueador;;  
                  public  Incrementador(Object  bloqueador)  {  
o                     this.bloqueador  =  bloqueador;;          
g                 }  
s                   
                  public  int  getTotal()  {    
p                     return  contador;;  
o                 }  
                    
t                 public  void  run()  {  
.                     synchronized(bloqueador)  {  
                          for(int  x  =  0  ;;  x  <  100  ;;  x++)  {  
c                             contador++;;  
o                             System.out.print(".");;  
m                             try  {  
                                  Thread.sleep(100);;  
                              }  catch(InterruptedException  ex){}  
                          }  
                          System.out.println();;  
                          bloqueador.notify();;  
                      }  
                  }  
              }  
                
           
         En   el   código   anterior,   no   se   ejecuta   la   sentencia   que   muestra   el   total   hasta   que   Incrementador   no   emite   el   notify   indicando   que  
         puede  continuar.  
         La   importancia   del   código   anterior   radica   en   que   para   poder   llamar   al   método   wait   del   objeto   bloqueador,   se   debe   de   poseer   el  
         bloqueo  del  mismo.  
             

           
Java  World     Capítulo  7       16  
  




Al  igual  que  sleep(),  wait()  contiene  una  sobrecarga:  wait(long  milisegundos).  Esto  tiene  como  propósito  poner  un  límite  de  tiempo  
                                                                                                                                                                           h
en  la  espera,  ejecutando  lo  que  ocurra  primero  (ya  sea  notify()  o  el  tiempo  ha  transcurrido).  
                                                                                                                                                                           t
  
                                                                                                                                                                           t
                          Cuando  se  ejecuta  un  notify()  no  quiere  decir  que  se  libere  el  bloqueo.  Esto  se  realizará  una  vez  que  se  salga               p
                          del  código  sincronizado.                                                                                                                       :
                                                                                                                                                                           /
                                                                                                                                                                           /
Utilizando  notifyAll()  cuando  varios  threads  puedan  estar  esperando                                                                                                 g
Si  más  de  un  thread  se  encontraba  esperando  que  se  le  notifique,  al  ejecutar  notifyAll()  todos  aquellos  que  se  encuentren  en   dichas  
                                                                                                                                                                           u
                                                                                                                                                                           s
                                                                                                                                                                           t
Utilizando  wait()  en  un  bucle  
                                                                                                                                                                           a
Uno  de  los  casos  que  podemos  encontrar  y  que  no  hemos  planteado  aun  es  el  hecho  de  que  el  notify()  se  ejecute  antes  que  el  wait().                v
¿Qué  pasaría  en  esta  situación?...  
                                                                                                                                                                           o
Simple,   si  un  objeto   estuviera   esperando  un  notify()  que   no  volverá  a   ejecutarse   (esto  es  así  por  nuestra  lógica   del  programa),   el  
                                                                                                                                                                           a
thread  estará  esperando  eternamente,  o  hasta  que  se  genere  una  interrupción  (InterruptedException).  
                                                                                                                                                                           l
                                                                                                                                                                           b
Capítulo  10  -­‐  Deployment                                                                                                                                              e
                                                                                                                                                                           r
Todo  desarrollo  en  Java  requiere  que  los  archivos  sean  pre-­‐compilados  a  bytecodes,  los  cuales  son  almacenados  en  archivos  .class,  o  
                                                                                                                                                                           o
porque  no  comprimir  todos  tus  .class  en  un  paquete  .jar.  
Un   recordatorio   que   mencionamos   en   el   primer   capítulo.   Para   poder   compilar   los   archivos   .java   debes   tener   instalada   alguna               l
versión  de  la  JDK  (Java  Development  Kit),  no  basta  con  tener  la  JRE  (Java  Runtime  Environment)  instalada.                                                  a
                                                                                                                                                                           .
Compilando  con  con  javac  
                                                                                                                                                                           b
Javac  es  el  comando  utilizado  para  poder  transformar  nuestros  .java  a  .class  (bytecodes).  La  sintaxis  de  este  es:                                         l
javac  [opciones]  [archivos  de  código  fuente]  
                                                                                                                                                                           o
Los  elementos  entre  []  significan  opcional.  
                                                                                                                                                                           g
Múltiples  opciones  y/o  archivos  de  código  fuente  deben  separarse  con  caracteres  de  espacio.  
                                                                                                                                                                           s
Opcion   d                                                                                                                                                                 p
Por  defecto,  cuando  compilemos  nuestros  archivos  en  Java,  el  directorio  destino  por  defecto  será  exactamente  el  mismo  que  el  de                         o
los  códigos  fuente.  Para  poder  modificar  esto  existe  el  comando   d.                                                                                              t
  
                                                                                                                                                                           .
                                                                                                                                                                           c
                           El  directorio  que  especifiques  mediante   d  debe  existir,  de  lo  contrario  generarás  un  error  de  compilación.                      o
                                                                                                                                                                           m  
  
                                            




  
17          Java  World     Capítulo  7  
           




         Supongamos  la  siguiente  estructura.  
h
t
                   Directorio  Raiz  
t
p
:                                       source  
/
                                                      com  
/
v                                                                    blogspot  
a                                                                                      gustavoalberola  
l
o                                                                                                               PruebaJavaWorld.java  

r                                       classes  
c                                                                                                                                                        
r        Dentro  de  source  van  nuestro  .java  y  dentro  de  classes  nuestros  .class.  
         Si  quisiéramos  compilar  el  código  anterior  (tengan  en  cuenta  que  según  la  estructura  anterior,  PruebaJavaWorld.java  esta  dentro  de  
e
         los  package  com,  blogspot  y  gustavoalberola)  deberíamos  utilizar  la  sintaxis:  
a          
t                                                                  
i                   javac   d  ../classes  com/blogspot/gustavoalberola/PruebaJavaWorld.java  
v          
o        Esto  lo  que  hará  es  crear  dentro  de  classes  la  misma  jerarquía  de  directorios,  con  el  .class  compilado  a  bytecode.  
.        Ejecutando  aplicaciones  con  java  
b
         Una  vez  que  tenemos  nuestros  .class  lo  que  necsitamos  es  ejecutar  el  programa,  para  ello  utilizamos  el  comando  java.  Su  sintaxis  es:  
l                  java  [opciones]  clase  [argumentos]  
o        Por   defecto,   el   comando   java   interpreta   que   lo   que   quieres   ejecutar      es   un   .class,   de   manera   que   no   es   necesario   especificar   la  
g        extensión  (es  más,  si  la  especificas,  no  podrás  ejecutar  tu  programa).  
s        Utilizandos  las  propiedades  de  sistema  
p
         Dentro  de  java  tenemos  una  clase  denominada  java.util.Properties.  Esta   es  utilizada  para  obtener  las  propiedades  por  defecto  del  
o
         sistema  operativo,  el  compilador  de  java,  la  jvm,  y  también  para  guardar  nuestras  propias  propiedades.  
t        Veamos  un  ejemplo  simple:  
.
c             import  java.util.Properties;;  
o               
              public  class  Pruebas_01  {  
m                 static  public  void  main(String[]  args)  {  
                      Properties  propiedades  =  System.getProperties();;  
                      propiedades.setProperty("MiPropiedad",  "MiValor");;  
                      propiedades.list(System.out);;  
                  }  
              }  
                
           
           
           
           
                                                        




           
Java  World     Capítulo  7     18  
  




Ejecutando  el  programa  con:  
                                                                                                                                                               h
           java  -­‐DMyOtraPripiedad="Aun  no  decido  que  valor  poner"  Pruebas_01  
                                                                                                                                                               t
El  resultado  es  algo  asi:  
                                                                                                                                                               t
                                                                                                                                                               p
                       java.runtime.name=Java(TM)  SE  Runtime  Environment  
                       sun.boot.library.path=C:Program  FilesJavajre6bin                                                                                   :
                       java.vm.version=14.3-­b01                                                                                                               /
                       java.vm.vendor=Sun  Microsystems  Inc.                                                                                                  /
                       java.vendor.url=http://java.sun.com/  
                                                                                                                                                               g
                       ...  
                       java.runtime.version=1.6.0_17-­b04                                                                                                      u
                       ...                                                                                                                                     s
                       java.specification.version=1.6                                                                                                          t
                       user.name=gustavo                                                                                                                       a
                       java.class.path=.  
                       MyOtraPripiedad=Aun  no  decido  que  valor  poner  
                                                                                                                                                               v
                       ...                                                                                                                                     o
                       MiPropiedad=MiValor                                                                                                                     a
                                                                                                                                                               l
                                                                                                                                                               b
Vemos  como  tanto  la  variable  que  declaramos  en  código,  como  aquella  que  introducimos  mediante   D  existen  en  el  listado  de  
propiedades.                                                                                                                                                   e
Manejando  argumentos  de  la  línea  de  comandos                                                                                                             r
                                                                                                                                                               o
Todos  losargumentos  que  se  escriban  en  el  momento  de  ejecución  entran  en  el  array  de  Strings  del  método  main,  empezando  por  el  
índice  0  para  el  primer  argumento,  y  así  sucesivamente.                                                                                                l
                                                                                                                                                               a
                                                                                                                                                               .
   public  class  Pruebas_02  {  
       static  public  void  main(String[]  args)  {                                                                                                           b
           int  x  =  0;;                                                                                                                                      l
           for(String  s  :  args)  {  
               System.out.println("Argumento  ["  +  x++  +  "]  =  "  +  s);;                                                                                 o
           }                                                                                                                                                   g
       }  
   }                                                                                                                                                           s
                                                                                                                                                               p
Ejecutando  el  comando                                                                                                                                        o
            java  Pruebas_02  soy1  "Y  yo  que?"  1234568                                                                                                     t
  
                                                                                                                                                               .
                      Argumento  [0]  =  soy1                                                                                                                  c
                      Argumento  [1]  =  Y  yo  que?                                                                                                           o
                      Argumento  [2]  =  1234568  
                                                                                                                                                               m  
  
                                         




  
19          Java  World     Capítulo  7  
           




         Buscando  otras  clases  
h
t        Cuando   compilamos   o   ejecutamos   una   aplicación,   esta   requiere   de   otras   clases   para   funcionar.   Supongamos   que   estamos   en   la  
t        sección  de  I/O,  y  necesitamos  la  clase  File,  esta  tendría  que  buscarse  en  java.io.File.  Para  ello,  java  realiza  las  siguientes  acciones:  

p                     Tanto  java  como  javac  buscan  otras  clases  de  la  misma  manera  
:                     Se  procede  a  buscar  una  a  una  las  clases  necesarias  
/                           o Se  busca  dentro  de  las  clases  que  vienen  estandar  con  J2SE  
/                           o Se  busca  dentro  de  los  classpath  declarados  
v                     La  búsqueda  se  detiene  en  la  primer  coincidencia.  
a                     El  classpath  puede  ser  declarado  de  dos  maneras:  
                            o Como  variable  del  sistema  operativo  
l
                            o Como   argumento   en   la   línea   de   comandos   (si   se   especifica,   sobrescribe   al   classpath   de   sistema,   solo   en   dicha  
o                               invocación).  
r
c        Declarando  y  utilizando  classpaths  
r        El  classpath  es  una  dirección  a  nivel  de  directorio  en  donde  se  buscaran  las  clases  necesarias  para  compilar/ejecutar  el  programa.  
e        El   classpath   a   su   vez   puede   estar   conformado   por   varios   classpath   concatenados   mediante   un   caracter   parser   que   hace   de  
a        separador.  
t        Hay  que  tener  en  cuenta  que  una  estructura  de  directorio  se  especifica  diferente  según  el  S.O.  que  estemos  utilizando:  

i                     Unix:  se  utiliza  como  directorio  el  /  y  como  separador  el  :  
v                     Windows:  se  utiliza  como  directorio  el    y  como  separador  el  ;.  
o        Un  ejemplo  de  classpath  válido  para  windows  sería:  
.                  .classes;c:misProyectosclasses;c:;  
b          
l        Muchas  veces  cuando  ejecutamos  un  programa  podemos  toparnos  con  una  excepción  ClassNotFoundException.  Esto  indica  que  
         la  JVM  no  pudo  localizar  alguna  clase  que  nuestro  programa  requiere.  
o
         Los  classpaths  se  recorren  de  izquierda  a  derecha.  
g          
s
                                      Cuando  se  utiliza  el  comando  java,  este  no  busca  en  el  directorio  donde  esta  parado  las  clases,  solo  en  el  
p
                                      directorio  de  la  JRE.  Para  que  haga  lo  primero,  es  necesario  especificarlo  mediante  la  opción   classpath  o  
o                                     cp.  
t
.          

c        Package  y  búsqueda  
o        Existen   dos   maneras   de   referenciar   clases   desde   nuestro   código   que   se   encuentran   en   otro   package,   mediante   imports,   o   la  
m        llamda  con  el  nombre  atómico  de  la  clase  (el  package.classNombre).  
           

              package  com.blogspot.gustavoalberola;;  
              public  class  JavaWorld  {}  
           
                                                        




           
Java  World     Capítulo  7      20  
  




Dicha  clase  será  almacenada  en  com/blogspot/gustavoalberola/JavaWorld.java.  
                                                                                                                                                                           h
Para  referenciarlo  desde  otro  package  podemos  utiliza  cualquiera  de  las  dos  sentencias  a  continuación:  
                                                                                                                                                                           t
Modo  de  referencia  atómico                                                                                                                                              t
                                                                                                                                                                           p
                                                                                                                                                                           :
     //otro  package  
     public  class  OtraClase  {                                                                                                                                           /
         static  public  void  main(String[]  args)  {                                                                                                                     /
             com.blogspot.gustavoalberola.JavaWorld  javaWorld;;  
             javaWorld  =  new  com.blogspot.gustavoalberola.JavaWorld();;  
                                                                                                                                                                           g
         }                                                                                                                                                                 u
     }                                                                                                                                                                     s
                                                                                                                                                                           t
Modo  de  referencia  mediante  imports                                                                                                                                    a
  
                                                                                                                                                                           v
                                                                                                                                                                           o
     //otro  package  
     //Tambien  podemos  utilizar  el  *  en  vez  de  JavaWorld  (importa  todas  las  clases  del                                                                        a
     package)                                                                                                                                                              l
     import  com.blogspot.gustavoalberola.JavaWorld;;    
                                                                                                                                                                           b
       
     public  class  OtraClase  {                                                                                                                                           e
         static  public  void  main(String[]  args)  {                                                                                                                     r
             JavaWorld  javaWorld;;  
             javaWorld  =  new  JavaWorld();;                                                                                                                              o
         }                                                                                                                                                                 l
     }  
                                                                                                                                                                           a
       
                                                                                                                                                                           .
Paths  relativos  y  absolutos                                                                                                                                             b
                                                                                                                                                                           l
La  diferencia  entre  un  path  relativo  y  absoluto  es:  
                                                                                                                                                                           o
          El  path  relativo  depende  de  donde  se  encuentra  el  directorio  actual.  Ejemplo:  ../  vuelve  un  directorio  hacia  arriba.                            g
          El   path   absoluto   siempre   referencia   al   mismo   lugar   sin   importar   donde   se   encuentre   el   directorio   actual.   Ejemplo:                s
          c:Jre_6_0_17.  
                                                                                                                                                                           p
Archivos  JAR                                                                                                                                                              o
                                                                                                                                                                           t
Teniendo   nuestra   aplicación   terminada,   es   probable   que   quieras   comenzar   a   distribuirla.   Puedes   tener   todos   los   .class   en   sus  
                                                                                                                                                                           .
respectivos  directorios  y  distribuirlos  solo  de  esa  manera,  o  puedes  generar  unn  archivo  jar  que  contenga  todos  los  .class.  
Algunas  reglas  con  respecto  a  los  .jar                                                                                                                               c
                                                                                                                                                                           o
          Automáticamente  genera  un  directorio  META-­‐INF.                                                                                                             m  
          Automáticamente  genera  un  archivo  MANIFEST.MF  dentro  del  directorio  anterior.  
          Jamás  introducirá  ninguna  de  tus  clases  dentro  del  directorio  META-­‐INF.  
          Se  copia  la  estructura  del  directorio  y  subdirectorios  tal  cual  estaba  en  el  file  system.  
          Los  comandos  java  y  javac  utilizan  el  .jar  con  una  estructura  de  directorio  normal.  


                           Cuando   queremos   compilar   o   ejecutar   una   clase   que   requiere   de   otra   que   se   encuentra   en   un   .jar,   es  
                           necesario  especificar  en  el  classpath  el  directorio  junto  con  el  nombre  y  extensión  del  .jar.    
                           Ejemplo:        java  -­‐cp=libs/JavaWorld.jar  HolaJavaWorld  

  


  
21          Java  World     Capítulo  7  
           




           
h
t                                                
t        Cuando   instanalamos   la   JRE,   dentro   de   uno   de   sus   directorios  
p        encontramos   jre/lib/ext.   Dentro   se   encuentran   todas   las   clases   que   java  
:        utiliza.   Si   pusiéramos   cualquiera   de   nuestras   clases   aquí   dentro,   no  
/        necesitaríamos  especificar  un  classpath  para  referenciarlas.    
/        Esto  es  una  práctica  poco  común,  y  solo  se  aconseja  para  casos  personales,  
v        pero  no  como  método  de  distribución  de  un  programa.  
         También   es   importante   saber   que   es   muy   común   encontrar   variables  
a
         definidas   para   abreviar   un   directorio,   como   por   ejemplo   JAVA_HOME.   Si  
l        ves  en  el  examen   esto,  interpretalo  como  el  directorio   de  las  librerías  de  
o        java.  
r
c
         Utilizando  import  estáticos                                                                      Fin  del  camino  
r        El  import  estático  se  utiliza  para  no  tener  que  escribir  el  nombre  completo            Con   esta   última   entrega   concluimos   la  
         de  la  constante,  método  o  atributo  estático.  Ejemplo:  
e                                                                                                           saga   de   Java   World   SCJP.   Ha   sido   un  
           
a                                                                                                           camino   largo   y   les   agradecemos   a   todos  
t           import  static  System.out;;                                                                    aquellos   que   nos   estuvieron   siguiendo  
              
i           public  class  HolaMundo  {                                                                     todo   este   tiempo,   a   aquellos   que  
v               static  public  void  main(String[]  args)  {                                               realizaron   comentarios   y   correcciones  
                    out.println("Hola  mundo");;  
o               }                                                                                           sobre   los   capítulos   previos,   y   a   la  
.           }                                                                                               comunidad  en  general.  
b                                                                                                             
l        Muchos  aseguran  que  esto  ahorra  un  par  de  tecleados  a  cambio  de  perder  
                                                                                                            Nos  quedan  un  par  de  cositas  para  subir  
o        en  la  redibilidad  del  código.  
                                                                                                            además   de   la   compilación   final   de  todos  
g
                                                                                                            los   capítulos   para   que   les   sea   más   fácil  
s                                     La  llamada  debe  ser  import  static,  y  solo  en                  descargarlos.  
p                                     ese  orden.  
                                                                                                              
o
                                                                                                            Esperamos   que   el   material   les   sea   de  
t          
.                                                                                                           ayuda   y   cualquier   duda   o   comentario  
c                                                                                                           que   tengan   no   duden   en   publicar   sus  
o                                                                                                           comentarios  en  el  blog.  
m                                                                                                             
                                                                                                            Gracias  a  todos!  
                                                                                                         




           
 
  




  

Capitulos 8 9-10

  • 1.
       
  • 2.
    Java  World    Capítulo  7   2     Capítulo  8    Clases  internas   h Una  clase  interna  básicamente  es  lo  que  el  nombre  indica,  una  clase  que  se  encuentra  dentro  de  otra  clase.  Existen  diferentes  tipos   t de  ellas,  y  las  maneras  de  instanciar  las  mismas  también  es  diferente,  de  manera  que  las  veremos  una  a  una.   t   p Durante  el  capítulo  veremos  4  conceptos:   : Clases  internas   / o Clases  internas  normales   / o Clases  internas  de  método   g o Clases  internas  anónimas   u Clases  estáticas  anidadas   s Algunas  reglas  sobre  las  clases  internas:   t a Tienen  acceso  a  todos  los  atributos  y  métodos  de  su  clase  contenedora,  por  más  que  los  mismos  sean  private.   v Debe  de  existir  una  instancia  de  la  clase  contenedora  para  poder  crear  una  instancia  de  la  clase  interna,  sin  excepción.   o Las  clases  internas  siempre  mantienen  una  referencia  a  la  clase  contenedora.   a Al  igual  que  las  clases  normales,  no  es  posible  definirlas  como  abstract  y  final.   l Clase  interna  normal   b e class  Externa  {   r    class  Interna  {   o    }   }   l   a Primer  punto  a  tener  en  cuenta,  es  que  este  código  al  precompilarlo  genera  dos  clases:   . b Externa.class   l Externa$Interna.class   o   g Una  clase  interna  no  puede  tener  métodos  estáticos.   s   p   o Instanciación   t . Desde  dentro  de  la  clase  externa,  la  clase  interna  es  visible,  de  manera  que  lo  siguiente  es  válido:     c o class  Externa  {   m      public  void  hazAlgo()  {          Interna  i  =  new  Interna();;      }        class  Interna  {      }   }   A  su  vez,  la  clase  interna  tiene  conocimiento  de  la  clase  externa,  pudiendo  acceder  a  sus  métodos  y  atributos  como  propios.        
  • 3.
    3   Java  World    Capítulo  7     Instanciación  fuera  de  la  clase   h t tiene  que  haber   t primero  una  instancia  de  la  clase  externa  para  que  pueda  existir  una  instancia  de  la  clase  interna   Bien,  según  el  código  anterior,  la  instanciación  de  ambas  clases  desde  fuera  de  la  clase  sería:   p : Externa  externa  =  new  Externa();;   / Externa.Interna  interna  =  externa.new  Interna();;   /   v a Referenciando  a  la  clase  externa  desde  la  interna   l Dado  que  el  modificador   this  se  encuentra  reservado  para  el  objeto  que  llamó  el  método  actual  en  ejecución,  no  nos  sirve  para   o invocar  otra  instancia.  Para  poder  referenciar  a  instancia  de  la  clase  externa  dentro  de  la  interna  la  sintaxis  sería:   [NombreClaseExterna].this   r c r class  Externa  {      class  Interna  {   e        public  void  hazAlgo()  {   a            Externa  externa  =  Externa.this;;  //Referencia  de  la  clase  contenedora   t            Interna  interna  =  this;;                  //Referencia  de  la  propia  clase  interna          }   i    }   v }       o . Modificadores  aplicables   b Los  modificadores  de  acceso  que  se  pueden  aplicar  a  la  clase  interna  normal  son:   l final   o abstract   g public   s private   p protected   o static  (transforma  la  clase  en  una  clase  común.  Lo  veremos  más  adelante)   t strictfp   . Clase  interna  de  método  local   c Es  posible  declarar  una  clase  interna  dentro  de  un  método.   o m   class  Externa  {      public  void  hazAlgo()  {          class  Interna  {              public  void  hazOtraCosa()  {}          }      }   }     El  que  hayas  declarado  una  clase  de  método  local  no  significa  que  hayas  creado  una  instancia  de  esta  clase.       De  manera  que  si  quisieramos  crear  una  instancia  de  Interna,  esto  solo  podría  realizarse  dentro  del  método  hazAlgo().      
  • 4.
    Java  World    Capítulo  7   4     Cosas  que  se  pueden  y  no  hacer  dentro  de  una  clase  interna  de  método   h t No  se  puede  acceder  a  las  variables  definidas  dentro  del  método,  salvo  que  estas  se  definan  como  final.   Puede  acceder  a  los  atributos  de  la  clase  externa.   t o Solo  podrá  acceder  a  atributos  estáticos,  si  es  que  fue  declarada  como  static  (no  existe  el  this).   p La   clase   puede   declararse   dentro   del   método,   pero   la   referencia   puede   almacenarse   en   otra   referencia,   de   manrea   que   : finalizado  el  método  el  objeto  siga  existiendo.   / / Modificadores  aplicables   g Los  modificadores  de  acceso  que  se  pueden  aplicar  a  una  clase  interna  de  método  local  son:   u abstract   s final   t Clases  internas  anónimas   a v Estas  conforman  las  porciones  de  código  más  extrañas  que  podamos  encontrar  en  Java.  Veamos  un  ejemplo  primero:   o a class  ClaseDos  {      public  void  hazAlgo()  {}   l }   b   class  Original  {   e    ClaseDos  c  =  new  ClaseDos()  {   r        public  void  hazAlgo()  {     o            System.out.println("Método  pop  sobrescrito");;          }   l    };;   a }   . b   l La  declaración  de  una  clase  anónima  debe  cerrar  la  última  llave  con  un  ;  (punto  y  coma),  salvo  que  se  este   definiendo  como  parámetro  de  un  método.   o g   s El  concepto  de  anónima  viene  porque  se  está  sobreescribiendo  una  clase  (o  interfaz),  pero  no  se  está  definiendo  un  nuevo  tipo.     p Conceptos  a  tener  en  cuenta  de  la  clase  anónima:   o t La   clase   anónima   puede   extender   de   una   clase   normal,     abstract   o   implementar   una   interface,   pero   solo   puede   . extender/implementar  de  una  de  las  anteriores  mencionadas  (no  puede  extender  de  a  e  implementar  la  interfaz  b).   Desde  fuera  de  la  clase  anónima  solo  se  pueden  invocar  los  métodos  definidos  en  la  super  clase  o  interfaz.   c Se  pueden  crear  nuevos  métodos,  pero  estos  solo  pueden  ser  invocados  desde  otro  método  de  la  clase  anónima.   o También  es  posible  crear  una  clase  anónima  como  parámetro  de  una  función.   m          
  • 5.
    5   Java  World    Capítulo  7     Veamos  un  ejemplo  de  una  clase  anónima  declarada  como  parámetro  de  un  método,  que  a  su  vez  extiende  de  una  clase  abstract.   h t class  Perro  {      public  void  perseguir(Gato  g)  {     t        System.out.println("El  perro  comienza  a  perseguir  al  gato");;   p        g.huir();;      }   : }   /   / abstract  class  Gato  {      abstract  public  void  huir();;   v }   a   class  Duenio  {   l    public  void  hazAlgo()  {   o        Perro  p  =  new  Perro();;   r        p.persegir(new  Gato()  {              public  void  huir()  {   c                System.out.println("El  gato  logró  huir  exitosamente");;   r            }          });;   e    }   a }     t i   El  perro  comienza  a  perseguir  al  gato   v El  gato  logró  huir  exitosamente   o .   b Crear  una  clase  anónima  a  partir  de  una  interfaz   l Una  clase  anónima  puede  implementar  una  interfaz,  pero  la  declaración  de  la  misma  no  es  como  se  hace  normalmente.  Veamos  un   o ejemplo:   g s interface  Animal  {   p    public  void  emitirSonido();;   }   o   t class  Familia  {      Animal  mascota  =  new  Animal()  {   .        public  void  emitirSonido()  {   c            System.out.println("wof  wof!");;   o        }      };;   m      mascota.emitirSonido();;   }         wof  wof!     Como  podemos  apreciar,  se  utiliza  tanto  clases  como  interfaces  de  la  misma  manera  en  cuanto  a  clases  anónimas  se  refiere.   new  [Class  o  Interface]()  {}        
  • 6.
    Java  World    Capítulo  7   6     Clases  estáticas  anidadas   h Una  clase  estática  anidada  es  simplemente  una  clase  definida  como  un  atributo  estático  de  la  clase  padre.   t   t Conceptos  que  cambian  con  respecto  a  las  clases  internas:   p No  requieren  de  una  clase  externa  para  poder  crear  una  instancia  de  la  interna.   : No  pueden  acceder  a  atributos  y  métodos  de  la  clase  externa  que  no  estén  definidos  como  static.   / Se  comporta  como  una  clase  normal,  solo  que  la  ruta  de  acceso  es  a  través  de  ClaseExterna.ClaseInterna.   / o Salvo   en   el   caso   que   estemos   en   un   método   de   la   clase   externa,   en   el   cual   la   clase   interna   puede   ser   accedida   g directamente  como  ClaseInterna.   u s class  Persona  {      static  class  Personita  {   t        public  void  hazAlgo()  {   a            System.out.println("Personita  hace  algo");;          }   v    }   o }   a   public  class  General  {   l       b    static  class  Cabo  {          public  void  hazAlgo()  {   e            System.out.println("Cabo  hace  algo");;   r        }      }   o    //  Tener  en  cuenta  que  el  método  main  está  definido  dentro  de  General   l    static  public  void  main(String[]  args)  {   a        Persona.Personita  p  =  new  Persona.Personita();;          Cabo  c  =  new  Cabo();;   .        p.hazAlgo();;  //  Personita  hace  algo   b        c.hazAlgo();;  //  Cabo  hace  algo      }   l }   o     g s p Capítulo  9    Hilos  de  ejecución  (Threads)   o Un  hilo  de  ejecución  es  un  proceso  liviano  desencadenado  por  otro  proceso,  y  dependiente  de  este  último.  El  nuevo  hilo  tendrá  un   t stack  aparte.   . En  palabras  más  simples,  un  hilo  de  ejecución  es  un  proceso  paralelo  con  respecto  al  proceso  principal,  lo  que  lleva  a  cabo  que  en   c computadoras  con  más  de  un  nucleo  (o  emulados),  haya  varios  procesos  ejecutando  nuestro  código  al  mismo  tiempo.   o   m   Que  representa  para  Java  un  Thread?   Una  clase  java.lang.Thread   Un  hilo  de  ejecución   Para  el  examen  es  necesario  conocer  cuando  una  sintaxis  está  creando  código  multithread  seguro  y  cuando  no.        
  • 7.
    7   Java  World    Capítulo  7     Creando  un  thread   h t Dentro  de  la  clase  java.lang.Thread  se  encuentran  una  serie  de  métodos.  Dentro  de  estos  deberás  de  conocer  los  siguientes:   t start()   p yield()   : sleep()   / run()   / Para  poder  crear  un  nuevo  Thread  debes  de  cumplir  el  contrato  de  la  interfaz  java.lang.Runnable,  el  cual  tiene  un  solo  método:   v public  void  run();   a Para  ello,  la  clase  que  utilicemos  tiene  que  implementar  dicha  interfaz,  o  extender  la  clase  java.lang.Thread.   l o Definiendo  un  Thread  extendiendo  Thread   r c class  MiClaseThread  extends  Thread  {   r    public  void  run()  {          System.out.println("Oh,  JavaWorld  esta  en  un  Thread!");;   e    }   a }     t   i Definiendo  un  Thread  implementando  Runnable   v o class  MiClaseRunnable  implements  Runnable  {   .    public  void  run()  {   b        System.out.println("Oh,  JavaWorld  esta  en  un  Thread!");;      }   l }   o     g Instanciando  un  Thread   s p Si  o  si  es  necesaria  una  instancia  de  Thread  para  poder  correr  un  hilo  de  ejecución.   o Para  eso  tenemos  dos  posibilidades,  dependiendo  de  si  extendimos  de  Thread,  o  implementamos  Runnable.   t Instanciando  un  Thread  que  extiende  de  Thread   . c Thread  hilo  =  new  miClaseConThread();;   o Creamos  un  objeto  MiClaseConThread  y  lo  asignamos  a  una  referencia  de  tipo  Thread,  dado  que  extiende  de  Thread,  la  relación  Is-­‐A   m   Thread  es  legal.   Instanciando  un  Thread  que  implementa  Runnable   Runnable  hiloRunnable  =  new  miClaseConThread();;   Thread  hilo  =  new  Thread(hiloRunnable);;   //  O  la  versión  abreviada   Thread  hilo  =  new  Thread(new  miClaseConThread());;   En  este  caso,  lo   que  hacemos  es  primero  crear  una   instancia  de  nuestra  clase  y  almacenarla   en  una   referencia  de  tipo  Runnable.   Luego,  utilizamos  uno  de  los  constructores  sobrecargados  de  Thread,  el  cual  recibe  un  objeto  de  tipo  Runnable.        
  • 8.
    Java  World    Capítulo  7   8     La  clase  Thread   h Como  mencionamos  anteriormente,  Thread  tiene  una  serie  de  constructores  sobrecargados:   t t Thread()   p Thread(Runnable  objetivo)   : Thread(Runnable  objetivo,  String  nombre)   Thread(String  nombre)   / / Si   probamos   los   códigos   anteriores   en   una   aplicación   en   Java,   notaríamos   que   no   pasa   nada.   La   cuestión   es   que   el   instanciar   un   g Thread   no   hace   que   se   lance   el   hilo   de   ejecución   del   mismo,   de   manera   que   no   se   ejecuta.   Para   poder   determinar   en   que   u condiciones  de  ejecución  se  encuentra  el  Thread  lo  podemos  clasificar  en  tres  estados:   s Estado   Descripción   t new   Cuando  un  Thread  ha  sido  instanciado  (invocación  del  new)  se  encuentra  en  estado  nuevo.   a (nuevo)   v alive     Cuando  el  hilo  de  ejecución  es  lanzado  (se  crea  un  nuevo  stack  para  el  hilo  y  se  ejecuta  el  contenido  de  run()  ),  se  dice   o (vivo)   que  el  Thread  está  vivo.   a dead   Cuando  el  hilo  de  ejecución  completa  el  método  run,  se  dice  que  el  Thread  está  muerto.   l (muerto)   b Iniciando  la  ejecución  de  un  Thread   e Simplemente,  para  iniciar  la  ejecución  de  un  nuevo  Thread,  se  utiliza  el  método  start().   r o Runnable  hiloRunnable  =  new  miClaseConThread();;   Thread  hilo  =  new  Thread(hiloRunnable);;   l hilo.start();;   a   . Tambien   hay   que   tener   mucho   cuidado   con   la   llamada   a   run().   Cuando   invocamos   el   método   start(),   este   primero   crea   un   nuevo   b stack,  y  luego  lanza  el  método  run()  como  miembro  inicial  de  dicho  stack  en  un  hilo  de  ejecución  aparte.     l   o Si  se  invoca  directamente  el  método  run()  no  generará  un  error,  pero  el  mismo  no  se  ejecutará  en  un  nuevo   g thread,  sino  que  sería  como  llamar  a  un  método  normal.   s p     o t . c o m    
  • 9.
    9   Java  World    Capítulo  7     Ejecutando  Threads   h t Vamos  a  lo  que  nos  concierne,  corramos  algunos  hilos:   t class  PruebasRunnable  implements  Runnable  {   p    private  int  iteraciones  =  4;;   :              public  void  run()  {   /        for  (int  x  =  0  ;;  x  <  iteraciones;;  x++  )  {   /            System.out.println("Ejecutando  ["  +  Thread.currentThread().getName()  +  "]  ["  +  x                                                      +  "]");;   v        }   a    }   l          static  public  void  main(String[]  args)  {   o        Runnable  hilo  =  new  PruebasRunnable();;   r                  Thread  hilo1  =  new  Thread(hilo,  "Hilo  1");;   c        Thread  hilo2  =  new  Thread(hilo,  "Hilo  2");;   r        Thread  hilo3  =  new  Thread(hilo,  "Hilo  3");;             e        hilo1.start();;   a        hilo2.start();;          hilo3.start();;   t    }   i }   v     o Ejecutando  [Hilo  1]  [0]   . Ejecutando  [Hilo  2]  [0]   b Ejecutando  [Hilo  3]  [0]   Ejecutando  [Hilo  2]  [1]   l Ejecutando  [Hilo  1]  [1]   o Ejecutando  [Hilo  2]  [2]   g Ejecutando  [Hilo  3]  [1]   s Ejecutando  [Hilo  2]  [3]   Ejecutando  [Hilo  1]  [2]   p Ejecutando  [Hilo  3]  [2]   o Ejecutando  [Hilo  1]  [3]   t Ejecutando  [Hilo  3]  [3]   .     c   o El  orden  de  ejecución  de  los  hilos  no  puede  ser  jamás  predecido.   m     Por  más  que  conozcamos  el  orden  en  que  son  inicializados,  ni  siquiera  esto  nos  asegura  de  que  el  orden  de  ejecución  de  los  mismos   sea  ese.   El  sistema  de  hilos  y  tareas  es  manejado  por  el  Sistema  Operativo  en  conjunto  con  la  JVM,  son  ellos  quienes  asignarán  el  proceso  y   otorgaran  los  tiempos  que  el  mismo  se  encuentra  en  ejecución.   Otra  cuestión  a  tener  en  cuenta  es  que  un  Thread  solo  puede  ser  llamado  una  única  vez  en  toda  su  existencia.     El   llamar   al   método   start()   más   de   una   vez   desde   el   mismo   Thread   generará   el   lanzamiento   de   una   excepción  IllegalThreadStateException.      
  • 10.
    Java  World    Capítulo  7   10     Estados  y  transiciones  de  los  threads   h En  total  podemos  contar  5  estados  en  los  cuales  puede  estar  un  thread.  Veamos  un  gráfico  de  esto  para  entender  un  poco  mejor:   t t Alive  (vivo)   p Waiting   : /Blocking   / New         (esperando   Dead   / (nuevo)   /bloqueado)   (muerto)   g u s t Runnable   Running           a (esperando   (en   v ejecución)   ejecución)   o a l b     e Tabla  de  estados   Estado   Descripción   r New   Este  estado  se  da  cuando  se  ha  invocado  al  new  del  Thread,  pero  aun  no  se  ha  llamado  al  método   o (nuevo)   start().   l Runnable   Este  estado  se  da  cuando  el  thread  se  encuentra  listo  para  ser  ejecutado,  y  está  esperando  que  el   a (esperando  ejecución)   gestionador  de  eventos  de  la  JVM  lo  seleccione  para  comenzar  la  ejecución.   . Running   Este  estado  se  da  cuando  el  thread  fue  seleccionado  por  el  gestionador  de  eventos  y  se  encuentra   b (en  ejecución)   actualmente  en  ejecución.   l Waiting/Block   Este  estado  se  da  cuando  el  thread  requiere  algún  recurso  (I/O  por  ejemplo),  de  manera  que  para   (esperando/bloqueado)   no  consumir  recursos  de  CPU  queda  esperando.  También  puede  pasar  que  se  le  haya  ordenado  que   o se  durmiera,  de  manera  que  despertará  cuando  acabe  el  tiempo  (si  se  especificó),  o  que  otro  thread   g le  envíe  una  señal  para  despertarlo.   s Dead   Este   estado   se   da   cuando   el   thread   completó   la   ejecución   del   método   run.   Aun   sigue   siendo   un   p (muerto)   objeto,  el  cual  solicito  que  se  liberarn  sus  recursos.   o Durmiendo  (Sleep)   t Sleep  es  un  método  estático  de  la  clase  Thread.  Este  solo  puede  afectar  al  Thread  que  actualmente  se  está  ejecutando,  de  manera   . que  un  Thread  no  puede  dormir  a  otro.   c Cuando  un  Thread     o Los  métodos  sleep  son:   m   sleep()   sleep(long  milisegundos)     El  segundo  lo  duerme  por  un  tiempo  determinado.   Cuando   se   especifica   un   tiempo   de   sleep,   este   representa   el   tiempo   mínimo   que   el   thread   permanecerá   dormido,  pero  no  es  el  tiempo  exacto.      
  • 11.
    11   Java  World    Capítulo  7     Además,  este  método  puede  generar  una  excepción  InterruptedException,  por  lo  que  hay  que  llamarlo  dentro  de  un  Try-­‐Catch.   h Hagamos  un  ejemplo  simple:   t t import  java.lang.InterruptedException;;   p   : public  class  PruebasRunnable01  implements  Runnable  {   /    static  public  void  main(String[]  args)  {          (new  Thread(new  PruebasRunnable01())).start();;   /    }   v          public  void  run()  {   a        for  (int  x  =  1  ;;  x  <=  101  ;;  x  ++)  {   l            if  (x%10  ==  0)  {                  System.out.println("Running  "  +  x);;   o            }   r            try  {   c                Thread.sleep(500);;  //  1  milisegundo  *  500  =  1/2  segundo              }  catch(InterruptedException  ex)  {}   r        }   e    }   }   a   t i Yield()  y  threads  con  prioridades   v Los  threads  siempre  se  ejecutan  con  una  prioridad,  generalmente,  esta  se  representa  con  un  número  del  1  al  10.   o Si  el   . thread   excede   el   tiempo,   se   pausa   su   ejecución,   y   se   devuelve   a   la   b thread  para  que  se  ejecute.  Otras  utilizan  una  lógica  que  permiten  a  un  thread  ejecutarse  hasta  la  finalización  del  método  run.   l   o   g s La  JVM  no  especifica  que  las  prioridades  se  sigan  al  pie  de  la  letra,  de  manera  que  solo  utilizamos  estas  para   p optimizar  el  código,  pero  no  dependan  de  ellas  para  determinar  la  lógica  del  programa.   o t   . Esto  nos  deja  con  dos  posibles  comportamientos:   c mplete  o  se  bloque.   o Se  utilizan  tiempos  máximos  de  ejecución,  de  manera  que  todos  los  threads  (o  la  gran  mayoría),  tengan  una  oportunidad  de   m   ejecutarse.   Estableciendo  la  prioridad  de  los  threads   El  thread  recibe  una   prioridad  por  defecto,  la  cual  corresponde  a   la   prioridad  del  thread  con  que  fue  creado.  Esta   comprende  un   rango  que  va  generalmente  del  1  al  10,  pero  no  todas  las  JVM´s  contienen  este  rango.   Por  defecto,  los  threads  main  son  creados  con  prioridad  5.   Existen  también  algunos  identificadores  en  la  clase  Thread  para  indicar  las  prioridades:   Thread.MIN_PRIORITY     1   Thread.NORM_PRIORITY     5   Thread.MAX_PRIORITY     10   La   prioridad   se   establece   mediante   el   método   setPriority(int   prioridad).   Este   es   un   método   de   instancia   perteneciente   a   la   clase   Thread.    
  • 12.
    Java  World    Capítulo  7   12     Ejemplo:   h Thread  t  =  new  MiThread();;   t t.setPriority(Thread.MAX_PRIORITY);;   t t.start();;     p La  JVM  nunca  cambiará  la  prioridad  de  un  thread.   : El  método  yield()   / Este  método  lo  que  hace  es  enviar  una  sugerencia   / hay  que  tener  en  cuenta  que  esto  es  una  sugerencia,  y  puede  que  nunca  se  cumpla.  También  puede  que  se  cumpla,  pero  al  enviar  el     g u Thread.   s t El  método  join()   a Este  método  permite  unir  la  ejecución  de  un  thread  al  final  de  la  otra.  Supongamos  que  tenemos  dos  threads  A  y  B.  A  requiere  que  B   v se  ejecute  para  poder  continuar,  de  manera  que  A  realiza  un  join  contra  B.  Cuando  B  termine  su  ejecución,  recién  en  ese  momento  A   o   Este  es  un  método  de  instancia  perteneciente  a  la  clase  Thread.   a l Sincronización  de  código   b La  sincronización  es  el  termino  utilizado  para  que  varios  elementos  que  utilizan  un  recurso  compartido  no  generen  inconsistencia  de   e datos.   r En  el  siguiente  ejemplo  de  código  pueden  ver  un  caso  en  particular  con  una  cuenta  bancaria.  Ejecutenlo  varias  veces  y  verán  como  a   o veces  el  saldo  queda  en  negativo  y  otras  no.     l Para  ver  el  ejemplo,  dirígete  al  enlace  y  compila  el  código.   a   . Lo  que  debemos  hacer   en  orden  de  preserva b atómica   (en   realidad   el   término   no   es   del   todo   correcto,   dado   que   una   operación   atómica   es   aquella   que   solo   contiene   una   l instrucción.  En  este  caso,  se  utiliza  para  identificar  un  conjunto  de  instrucciones  que  deben  de  procesarse  como  una  sola).   o Para   ello   podemos   utilizar   el   modificador   synchronized.   Este   lo   que   hace   es   asegurarse   de   que   solo   un   objeto   por   vez   pueda   g acceder  al  recurso  (en  este  caso  el  método),  pero  no  asegura  que  el  objeto  ejecute  en  una  pasada  todo  el  código.     Si   un   objeto   ejecuta   el   código   y   se   interrumpe   dentro   del   mismo,   se   mantiene   una   llave,   de   manera   que   otro   objeto   no   pueda   s acceder  hasta  que  el  que  estaba  bloqueado,  vuelva  y  termine  con  la  ejecución.   p   o Veamos  el  mismo  ejemplo  pero  ahora  sincronizado.  Ejecutenlo  las  veces  que  quieran.  Verán  que  el  saldo  de  la  cuenta  jamás  será   t negativo.   .   c Para  ver  el  ejemplo,  dirígete  al  enlace  y  compila  el  código.   o     m    
  • 13.
    13   Java  World    Capítulo  7     Sincronización  y  bloqueos   h t La   sincronización   funciona   mediante   bloqueos.   Denominamos   bloqueo   al   método   que   implementa   synchronized,   y   monitor   al   t objeto  que  accede  al  bloqueo.   Puntos  clave  sobre  synchronized:   p : Solo  se  pueden  sincronizar  métodos  o  bloques  de  código.   / Cada  objeto  solo  tiene  un  bloqueo.   / No  es  necesario  sincronizar  todos  los  métodos  de  una  clase.   v Solo  puede  acceder  un  monitor  al  bloqueo  por  vez.   a Si   se   utiliza   la   sincronización   en   forma   incorrecta,   se   pueden   llegar   a   generar   deadlocks   (bloqueos   de   la   muerte).   Esto   sucede  cuando  dos  objetos,  contienen  un  bloqueo,  y  ambos  requieren  acceder  al  bloqueo  del  contrario.   l tor).   o Un  thread  puede  adquirir  más  de  un  bloqueo.   r Es  posible  sincronizar  un  bloque  de  código  en  vez  de  un  método  completo.   c r   e //Método  de  instancia  sincronizado   a public  synchronized  hazAlgo()  {      System.out.println("Codigo  sincronizado");;   t }   i //Bloque  de  código  de  instancia  sincronizado   public  void  hazAlgo()  {   v    synchronized(this)  {   o        System.out.println("Codigo  sincronizado");;   .    }   }   b //Método  de  clase  sincronizado   l static  public  synchronized  hazAlgo()  {      System.out.println("Static  -­  Codigo  sincronizado");;   o }   g //Bloque  de  código  de  clase  sincronizado   static  public  hazAlgo()  {   s    synchronized(MyClase.class)  {   p        System.out.println("Static  -­  Codigo  sincronizado");;   o    }   }   t     . c o m    
  • 14.
    Java  World    Capítulo  7   14     Que  pasa  si  un  thread  no  obtiene  el  bloqueo?   h Si  un  objeto  intenta  acceder  a  por  ejemplo  un  método  sincronizado,  y  este  ya  está  bloqueado,  el  objeto  en  cuestión  queda  en  una   t lista  de  espera  especial  para  cuando  el  bloqueo  sea  liberado.   t No  hay  una  lógica  que  indique  en  que  orden  se  obtiene  el  próximo  objeto  que  se  encuentra  en  la  lista  esperando  el  bloqueo.   p Cuadro  de  cómo  afectan  los  métodos  de  threads  a  los  bloqueos   : Libera  el  bloqueo   Mantiene  el  bloqueo   Clase  que  contiene  el  método   / wait()   notify()   java.lang.Object     join()   java.lang.Thread   /   sleep()   java.lang.Thread   g   yield()   java.lang.Thread   u Cuando  es  necesario  sincronizar?   s Generalmente,  siempre  que  utilicemos  threads  será  necesario  que  hagamos  uso  de  la  sincronización,  siempre  que  tanto  en  métodos   t estáticos  como  no  estáticos,  haya  datos  que  puedan  sufrir  modificaciones  y  que  no  sean  de  tipo  local,  se  deberán  de  marcar  como   a synchronized.   v Hay  un  pequeño  tema,  dijimos  que  cada  clase  tiene  un  bloqueo  disponible,  pero  es  uno  para  la  clase  y  uno  para  la  instancia  (static   o y  no  static).  El  problema  es  que  si  un  método  de  clase  llama  a  un  atributo  estático,  y  el  primero  está  sincronizado,  solo  se  toma  un   a bloqueo,  el  de  la  clase.  Y  si  otro  objeto  llama  al  método  estático,  y  este  llama  al  atributo  de  clase,  solo  se  toma  el  bloqueo  estático.  Y   l con  esto  ambos  objetos  pudieron  saltear  los  bloqueos  del  otro.     De  más  está  decir  que  esta  situación  debes  evitarla  siempre  que  sea  posible  de  manera  que:   b e Los  atributos  estáticos  solo  se  deben  invocar  desde  métodos  estáticos  sincronizados.   r Los  atributos  de  clase  solo  se  deben  invocar  desde  métodos  de  clase  sincronizados.   o l Clases  multi-­‐hilo  seguro   a Cuando   una   clase   contiene   métodos   synchronized   cuidadosamente   colocados,   se   denomina   que   la   clase   es   multi-­‐hilo   seguro   . (Thread-­‐Safe).   Pero   hay   un   problema,   que   la   clase   sea   thead-­‐safe   no   quita   que   podamos   implementarla   de   manera   incorrecta,   produciendo  posibles  corrupciones  de  datos.   b De  manera  que  cuando  utilicemos  threads,  debemos  depender  de  la  clase  que  llevaría  a  cabo  la  operación  atómica.   l o Bloqueos  de  la  muerte   g Esto  se  produce  cuando  dos  bloqueos  esperan  que  se  libere  el  bloqueo  del  contrario  para  poder  continuar.  Esto  generalmente  es  un   s error  muy  difícil  de  detectar,  además  de  que  cuando  trabajamos  con  threads,  el  reproducir  el  error  es  aun  más  complicado.   p Interacción  entre  threads   o Para  comunicarse  entre  si,  se  utilizan  los  método:  wait(),  notify()  y  notifyAll().   t   . c wait(),  notify(),  notifyAll()  solo  pueden  ser  invocados  desde  un  contexto  sincronizado.  Un  objeto  no  puede   o ionvocar  dichos  métodos  a  menos  que  posea  el  bloqueo.   m     Los  métodos  wait()  y  notify()  pertenecen  a  la  clase  Object.   Un  objeto  puede  tener  una  lista  con  0  ..  *  (0  a   muchos)  objetos  esperando  que  se  les  notifique  cuando  la  ejecución  de  este  haya   terminado,  o  el  bloqueo  se  haya  liberado.  Veamos  un  ejemplo:    
  • 15.
    15   Java  World    Capítulo  7       h t //Compilación:   javac  -­g  PruebasRunnable04.java   //Ejecución:     java  PruebasRunnable04   t   p public  class  PruebasRunnable04  {      static  public  void  main(String[]  args)  {   :        (new  PruebasRunnable04(new  Object())).pruebaWait();;   /    }   /          private  Object  bloqueador;;   v       a    public  PruebasRunnable04(Object  bloqueador)  {          this.bloqueador  =  bloqueador;;   l    }   o       r    public  void  pruebaWait()  {          Incrementador  incrementador  =  new  Incrementador(bloqueador);;   c        (new  Thread(incrementador)).start();;   r          synchronized(bloqueador)  {   e            try  {   a                System.out.println("Esperando  a  que  se  complete  el  incrementador...");;                  bloqueador.wait();;   t            }  catch(InterruptedException  ex)  {}   i            System.out.println("El  total  es:  "  +  incrementador.getTotal());;   v        }      }   o       . }   class  Incrementador  implements  Runnable  {   b    private  int  contador  =  0;;   l    private  Object  bloqueador;;      public  Incrementador(Object  bloqueador)  {   o        this.bloqueador  =  bloqueador;;           g    }   s          public  int  getTotal()  {     p        return  contador;;   o    }         t    public  void  run()  {   .        synchronized(bloqueador)  {              for(int  x  =  0  ;;  x  <  100  ;;  x++)  {   c                contador++;;   o                System.out.print(".");;   m                  try  {                      Thread.sleep(100);;                  }  catch(InterruptedException  ex){}              }              System.out.println();;              bloqueador.notify();;          }      }   }       En   el   código   anterior,   no   se   ejecuta   la   sentencia   que   muestra   el   total   hasta   que   Incrementador   no   emite   el   notify   indicando   que   puede  continuar.   La   importancia   del   código   anterior   radica   en   que   para   poder   llamar   al   método   wait   del   objeto   bloqueador,   se   debe   de   poseer   el   bloqueo  del  mismo.        
  • 16.
    Java  World    Capítulo  7   16     Al  igual  que  sleep(),  wait()  contiene  una  sobrecarga:  wait(long  milisegundos).  Esto  tiene  como  propósito  poner  un  límite  de  tiempo   h en  la  espera,  ejecutando  lo  que  ocurra  primero  (ya  sea  notify()  o  el  tiempo  ha  transcurrido).   t   t Cuando  se  ejecuta  un  notify()  no  quiere  decir  que  se  libere  el  bloqueo.  Esto  se  realizará  una  vez  que  se  salga   p del  código  sincronizado.   :   /   / Utilizando  notifyAll()  cuando  varios  threads  puedan  estar  esperando   g Si  más  de  un  thread  se  encontraba  esperando  que  se  le  notifique,  al  ejecutar  notifyAll()  todos  aquellos  que  se  encuentren  en   dichas   u   s t Utilizando  wait()  en  un  bucle   a Uno  de  los  casos  que  podemos  encontrar  y  que  no  hemos  planteado  aun  es  el  hecho  de  que  el  notify()  se  ejecute  antes  que  el  wait().   v ¿Qué  pasaría  en  esta  situación?...   o Simple,   si  un  objeto   estuviera   esperando  un  notify()  que   no  volverá  a   ejecutarse   (esto  es  así  por  nuestra  lógica   del  programa),   el   a thread  estará  esperando  eternamente,  o  hasta  que  se  genere  una  interrupción  (InterruptedException).   l b Capítulo  10  -­‐  Deployment   e r Todo  desarrollo  en  Java  requiere  que  los  archivos  sean  pre-­‐compilados  a  bytecodes,  los  cuales  son  almacenados  en  archivos  .class,  o   o porque  no  comprimir  todos  tus  .class  en  un  paquete  .jar.   Un   recordatorio   que   mencionamos   en   el   primer   capítulo.   Para   poder   compilar   los   archivos   .java   debes   tener   instalada   alguna   l versión  de  la  JDK  (Java  Development  Kit),  no  basta  con  tener  la  JRE  (Java  Runtime  Environment)  instalada.   a . Compilando  con  con  javac   b Javac  es  el  comando  utilizado  para  poder  transformar  nuestros  .java  a  .class  (bytecodes).  La  sintaxis  de  este  es:   l javac  [opciones]  [archivos  de  código  fuente]   o Los  elementos  entre  []  significan  opcional.   g Múltiples  opciones  y/o  archivos  de  código  fuente  deben  separarse  con  caracteres  de  espacio.   s Opcion   d   p Por  defecto,  cuando  compilemos  nuestros  archivos  en  Java,  el  directorio  destino  por  defecto  será  exactamente  el  mismo  que  el  de   o los  códigos  fuente.  Para  poder  modificar  esto  existe  el  comando   d.   t   .   c El  directorio  que  especifiques  mediante   d  debe  existir,  de  lo  contrario  generarás  un  error  de  compilación.   o m          
  • 17.
    17   Java  World    Capítulo  7     Supongamos  la  siguiente  estructura.   h t Directorio  Raiz   t p : source   / com   / v blogspot   a gustavoalberola   l o PruebaJavaWorld.java   r classes   c   r Dentro  de  source  van  nuestro  .java  y  dentro  de  classes  nuestros  .class.   Si  quisiéramos  compilar  el  código  anterior  (tengan  en  cuenta  que  según  la  estructura  anterior,  PruebaJavaWorld.java  esta  dentro  de   e los  package  com,  blogspot  y  gustavoalberola)  deberíamos  utilizar  la  sintaxis:   a   t     i javac   d  ../classes  com/blogspot/gustavoalberola/PruebaJavaWorld.java   v   o Esto  lo  que  hará  es  crear  dentro  de  classes  la  misma  jerarquía  de  directorios,  con  el  .class  compilado  a  bytecode.   . Ejecutando  aplicaciones  con  java   b Una  vez  que  tenemos  nuestros  .class  lo  que  necsitamos  es  ejecutar  el  programa,  para  ello  utilizamos  el  comando  java.  Su  sintaxis  es:   l   java  [opciones]  clase  [argumentos]   o Por   defecto,   el   comando   java   interpreta   que   lo   que   quieres   ejecutar     es   un   .class,   de   manera   que   no   es   necesario   especificar   la   g extensión  (es  más,  si  la  especificas,  no  podrás  ejecutar  tu  programa).   s Utilizandos  las  propiedades  de  sistema   p Dentro  de  java  tenemos  una  clase  denominada  java.util.Properties.  Esta   es  utilizada  para  obtener  las  propiedades  por  defecto  del   o sistema  operativo,  el  compilador  de  java,  la  jvm,  y  también  para  guardar  nuestras  propias  propiedades.   t Veamos  un  ejemplo  simple:   . c import  java.util.Properties;;   o   public  class  Pruebas_01  {   m      static  public  void  main(String[]  args)  {          Properties  propiedades  =  System.getProperties();;          propiedades.setProperty("MiPropiedad",  "MiValor");;          propiedades.list(System.out);;      }   }                  
  • 18.
    Java  World    Capítulo  7   18     Ejecutando  el  programa  con:   h java  -­‐DMyOtraPripiedad="Aun  no  decido  que  valor  poner"  Pruebas_01   t El  resultado  es  algo  asi:     t p java.runtime.name=Java(TM)  SE  Runtime  Environment   sun.boot.library.path=C:Program  FilesJavajre6bin   : java.vm.version=14.3-­b01   / java.vm.vendor=Sun  Microsystems  Inc.   / java.vendor.url=http://java.sun.com/   g ...   java.runtime.version=1.6.0_17-­b04   u ...   s java.specification.version=1.6   t user.name=gustavo   a java.class.path=.   MyOtraPripiedad=Aun  no  decido  que  valor  poner   v ...   o MiPropiedad=MiValor   a     l   b Vemos  como  tanto  la  variable  que  declaramos  en  código,  como  aquella  que  introducimos  mediante   D  existen  en  el  listado  de   propiedades.   e Manejando  argumentos  de  la  línea  de  comandos   r o Todos  losargumentos  que  se  escriban  en  el  momento  de  ejecución  entran  en  el  array  de  Strings  del  método  main,  empezando  por  el   índice  0  para  el  primer  argumento,  y  así  sucesivamente.   l   a . public  class  Pruebas_02  {      static  public  void  main(String[]  args)  {   b        int  x  =  0;;   l        for(String  s  :  args)  {              System.out.println("Argumento  ["  +  x++  +  "]  =  "  +  s);;   o        }   g    }   }   s     p Ejecutando  el  comando   o java  Pruebas_02  soy1  "Y  yo  que?"  1234568   t   . Argumento  [0]  =  soy1   c Argumento  [1]  =  Y  yo  que?   o Argumento  [2]  =  1234568   m          
  • 19.
    19   Java  World    Capítulo  7     Buscando  otras  clases   h t Cuando   compilamos   o   ejecutamos   una   aplicación,   esta   requiere   de   otras   clases   para   funcionar.   Supongamos   que   estamos   en   la   t sección  de  I/O,  y  necesitamos  la  clase  File,  esta  tendría  que  buscarse  en  java.io.File.  Para  ello,  java  realiza  las  siguientes  acciones:   p Tanto  java  como  javac  buscan  otras  clases  de  la  misma  manera   : Se  procede  a  buscar  una  a  una  las  clases  necesarias   / o Se  busca  dentro  de  las  clases  que  vienen  estandar  con  J2SE   / o Se  busca  dentro  de  los  classpath  declarados   v La  búsqueda  se  detiene  en  la  primer  coincidencia.   a El  classpath  puede  ser  declarado  de  dos  maneras:   o Como  variable  del  sistema  operativo   l o Como   argumento   en   la   línea   de   comandos   (si   se   especifica,   sobrescribe   al   classpath   de   sistema,   solo   en   dicha   o invocación).   r c Declarando  y  utilizando  classpaths   r El  classpath  es  una  dirección  a  nivel  de  directorio  en  donde  se  buscaran  las  clases  necesarias  para  compilar/ejecutar  el  programa.   e El   classpath   a   su   vez   puede   estar   conformado   por   varios   classpath   concatenados   mediante   un   caracter   parser   que   hace   de   a separador.   t Hay  que  tener  en  cuenta  que  una  estructura  de  directorio  se  especifica  diferente  según  el  S.O.  que  estemos  utilizando:   i Unix:  se  utiliza  como  directorio  el  /  y  como  separador  el  :   v Windows:  se  utiliza  como  directorio  el    y  como  separador  el  ;.   o Un  ejemplo  de  classpath  válido  para  windows  sería:   . .classes;c:misProyectosclasses;c:;   b   l Muchas  veces  cuando  ejecutamos  un  programa  podemos  toparnos  con  una  excepción  ClassNotFoundException.  Esto  indica  que   la  JVM  no  pudo  localizar  alguna  clase  que  nuestro  programa  requiere.   o Los  classpaths  se  recorren  de  izquierda  a  derecha.   g   s Cuando  se  utiliza  el  comando  java,  este  no  busca  en  el  directorio  donde  esta  parado  las  clases,  solo  en  el   p directorio  de  la  JRE.  Para  que  haga  lo  primero,  es  necesario  especificarlo  mediante  la  opción   classpath  o   o cp.   t .   c Package  y  búsqueda   o Existen   dos   maneras   de   referenciar   clases   desde   nuestro   código   que   se   encuentran   en   otro   package,   mediante   imports,   o   la   m   llamda  con  el  nombre  atómico  de  la  clase  (el  package.classNombre).     package  com.blogspot.gustavoalberola;;   public  class  JavaWorld  {}          
  • 20.
    Java  World    Capítulo  7   20     Dicha  clase  será  almacenada  en  com/blogspot/gustavoalberola/JavaWorld.java.   h Para  referenciarlo  desde  otro  package  podemos  utiliza  cualquiera  de  las  dos  sentencias  a  continuación:   t Modo  de  referencia  atómico   t   p : //otro  package   public  class  OtraClase  {   /    static  public  void  main(String[]  args)  {   /        com.blogspot.gustavoalberola.JavaWorld  javaWorld;;          javaWorld  =  new  com.blogspot.gustavoalberola.JavaWorld();;   g    }   u }   s   t Modo  de  referencia  mediante  imports   a   v o //otro  package   //Tambien  podemos  utilizar  el  *  en  vez  de  JavaWorld  (importa  todas  las  clases  del   a package)   l import  com.blogspot.gustavoalberola.JavaWorld;;     b   public  class  OtraClase  {   e    static  public  void  main(String[]  args)  {   r        JavaWorld  javaWorld;;          javaWorld  =  new  JavaWorld();;   o    }   l }   a     . Paths  relativos  y  absolutos   b l La  diferencia  entre  un  path  relativo  y  absoluto  es:   o El  path  relativo  depende  de  donde  se  encuentra  el  directorio  actual.  Ejemplo:  ../  vuelve  un  directorio  hacia  arriba.   g El   path   absoluto   siempre   referencia   al   mismo   lugar   sin   importar   donde   se   encuentre   el   directorio   actual.   Ejemplo:   s c:Jre_6_0_17.   p Archivos  JAR   o t Teniendo   nuestra   aplicación   terminada,   es   probable   que   quieras   comenzar   a   distribuirla.   Puedes   tener   todos   los   .class   en   sus   . respectivos  directorios  y  distribuirlos  solo  de  esa  manera,  o  puedes  generar  unn  archivo  jar  que  contenga  todos  los  .class.   Algunas  reglas  con  respecto  a  los  .jar   c o Automáticamente  genera  un  directorio  META-­‐INF.   m   Automáticamente  genera  un  archivo  MANIFEST.MF  dentro  del  directorio  anterior.   Jamás  introducirá  ninguna  de  tus  clases  dentro  del  directorio  META-­‐INF.   Se  copia  la  estructura  del  directorio  y  subdirectorios  tal  cual  estaba  en  el  file  system.   Los  comandos  java  y  javac  utilizan  el  .jar  con  una  estructura  de  directorio  normal.   Cuando   queremos   compilar   o   ejecutar   una   clase   que   requiere   de   otra   que   se   encuentra   en   un   .jar,   es   necesario  especificar  en  el  classpath  el  directorio  junto  con  el  nombre  y  extensión  del  .jar.     Ejemplo:        java  -­‐cp=libs/JavaWorld.jar  HolaJavaWorld      
  • 21.
    21   Java  World    Capítulo  7       h t   t Cuando   instanalamos   la   JRE,   dentro   de   uno   de   sus   directorios   p encontramos   jre/lib/ext.   Dentro   se   encuentran   todas   las   clases   que   java   : utiliza.   Si   pusiéramos   cualquiera   de   nuestras   clases   aquí   dentro,   no   / necesitaríamos  especificar  un  classpath  para  referenciarlas.     / Esto  es  una  práctica  poco  común,  y  solo  se  aconseja  para  casos  personales,   v pero  no  como  método  de  distribución  de  un  programa.   También   es   importante   saber   que   es   muy   común   encontrar   variables   a definidas   para   abreviar   un   directorio,   como   por   ejemplo   JAVA_HOME.   Si   l ves  en  el  examen   esto,  interpretalo  como  el  directorio   de  las  librerías  de   o java.   r c Utilizando  import  estáticos   Fin  del  camino   r El  import  estático  se  utiliza  para  no  tener  que  escribir  el  nombre  completo   Con   esta   última   entrega   concluimos   la   de  la  constante,  método  o  atributo  estático.  Ejemplo:   e saga   de   Java   World   SCJP.   Ha   sido   un     a camino   largo   y   les   agradecemos   a   todos   t import  static  System.out;;   aquellos   que   nos   estuvieron   siguiendo     i public  class  HolaMundo  {   todo   este   tiempo,   a   aquellos   que   v    static  public  void  main(String[]  args)  {   realizaron   comentarios   y   correcciones          out.println("Hola  mundo");;   o    }   sobre   los   capítulos   previos,   y   a   la   . }   comunidad  en  general.   b       l Muchos  aseguran  que  esto  ahorra  un  par  de  tecleados  a  cambio  de  perder   Nos  quedan  un  par  de  cositas  para  subir   o en  la  redibilidad  del  código.     además   de   la   compilación   final   de  todos   g los   capítulos   para   que   les   sea   más   fácil   s La  llamada  debe  ser  import  static,  y  solo  en   descargarlos.   p ese  orden.     o Esperamos   que   el   material   les   sea   de   t   .   ayuda   y   cualquier   duda   o   comentario   c   que   tengan   no   duden   en   publicar   sus   o comentarios  en  el  blog.   m     Gracias  a  todos!      
  • 22.