Modificadores en Java

Modificadores de acceso: public, private, protected y default

Los modificadores de acceso, como su nombre indica, determinan desde qué clases se puede acceder a un determinado elemento. En Java tenemos 4 tipos: public, private, protected y el tipo por defecto, que no tiene ninguna palabra clave asociada, pero se suele conocer como default o package-private.

Si no especificamos ningún modificador de acceso se utiliza el nivel de acceso por defecto, que consiste en que el elemento puede ser accedido sólo desde las clases que pertenezcan al mismo paquete.

El nivel de acceso public permite a acceder al elemento desde cualquier clase, independientemente de que esta pertenezca o no al paquete en que se encuentra el elemento.

private, por otro lado, es el modificador más restrictivo y especifica que los elementos que lo utilizan sólo pueden ser accedidos desde la clase en la que se encuentran. Este modificador sólo puede utilizarse sobre los miembros de una clase y sobre interfaces y clases internas, no sobre clases o interfaces de primer nivel, dado que esto no tendría sentido.

Es importante destacar también que private convierte los elementos en privados para otras clases, no para otras instancias de la clase. Es decir, un objeto de una determinada clase puede acceder a los miembros privados de otro objeto de la misma clase, por lo que algo como lo siguiente sería perfectamente válido:

class MiObjeto {
  private short valor = 0;

  MiObjeto(MiObjeto otro) {
    valor = otro.valor;
  }
}

El modificador protected, por último, indica que los elementos sólo pueden ser accedidos desde su mismo paquete (como el acceso por defecto) y desde cualquier clase que extienda la clase en que se encuentra, independientemente de si esta se encuentra en el mismo paquete o no. Este modificador, como private, no tiene sentido a nivel de clases o interfaces no internas.

Los distintos modificadores de acceso quedan resumidos en la siguiente tabla:

Modificadores de acceso
La misma clase Otra clase del mismo paquete Subclase de otro paquete Otra clase de otro paquete
public X X X X
protected X X X
default X X
private X

static

A pesar de lo que podría parecer por su nombre, heredado de la terminología de C++, el modificador static no sirve para crear constantes, sino para crear miembros que pertenecen a la clase, y no a una instancia de la clase. Esto implica, entre otras cosas, que no es necesario crear un objeto de la clase para poder acceder a estos atributos y métodos. Este es el motivo por el cual es obligatorio que main se declare como static; de esta forma no tenemos que ofrecer un constructor vacío para la clase que contiene el método, o indicar de alguna forma a la máquina virtual cómo instanciar la clase.

Un uso del modificador static sería, por ejemplo, crear un contador de los objetos de la clase que se han creado, incrementando la variable estática en el constructor:

class Usuario {
  static int usuarios = 0;

  Usuario() {
    usuarios++;
  }
}

Como es de esperar, dado que tenemos acceso a los atributos sin necesidad de crear un objeto, los atributos estáticos como usuarios no se inicializan al crear el objeto, sino al cargar la clase.

Podemos acceder a estos métodos y atributos bien desde la propia clase

public class Ejemplo {
  public static void main(String[] args) {
    Usuario raul = new Usuario();
    Usuario juan = new Usuario();
    System.out.println("Hay " + Usuario.usuarios + " usuarios");
  }
}

o bien desde una instancia cualquiera de la clase:

public class Ejemplo {
  public static void main(String[] args) {
    Usuario raul = new Usuario();
    Usuario juan = new Usuario();
    System.out.println("Hay " + raul.usuarios + " usuarios");
  }
}

Otro uso sería el de crear una recopilación de métodos y atributos relacionados a los que poder acceder sin necesidad de crear un objeto asociado, que podría no tener sentido o no ser conveniente, como es el caso de la clase Math.

public class Ejemplo {
  public static void main(String[] args) {
    System.out.println("PI es " + Math.PI);
    System.out.println("El coseno de 120 es " + Math.cos(120));
  }
}

Una característica no muy conocida que se introdujo en Java 1.5 son los static imports, una sentencia similar al import habitual, con la salvedad de que esta importa miembros estáticos de las clases, en lugar de clases de los paquetes, permitiendo utilizar estos miembros sin indicar el espacio de nombres en el que se encuentran. El ejemplo anterior podría haberse escrito también de la siguiente forma utilizando esta característica:

import static java.lang.Math.*;

public class Ejemplo {
  public static void main(String[] args) {
    System.out.println("PI es " + Math.PI);
    System.out.println("El coseno de 120 es " + Math.cos(120));
  }
}

Si por algún motivo requerimos cualquier tipo de computación para inicializar nuestras variables estáticas, utilizaremos lo que se conoce como bloque estático o inicializador estático, el cuál se ejecuta una sola vez, cuando se carga la clase.

public class Reunion {
  static {
    int zona_horaria = Calendar.getInstance().get(Calendar.ZONE_OFFSET)
      / (60 * 60 * 1000);
  }
}

Por último, una curiosidad relacionada que podéis utilizar para romper el hielo con una programadora Java es que podemos utilizar un bloque static para escribir un programa sencillo sin necesidad de un main, añadiendo una llamada a System.exit para que el programa termine tras cargar la clase sin intentar llamar al método main 😉

public class Ejemplo {
  static {
    System.out.println("Hola mundo");
    System.exit(0);
  }
}

strictfp

strictfp es un modificador de lo más esotérico, muy poco utilizado y conocido cuyo nombre procede de strict floating point, o punto flotante estricto.

Su uso sobre una clase, interfaz o método sirve para mejorar su portabilidad haciendo que los cálculos con números flotantes se restrinjan a los tamaños definidos por el estándar de punto flotante de la IEEE (float y double), en lugar de aprovechar toda la precisión que la plataforma en la que estemos corriendo el programa pudiera ofrecernos.

No es aconsejable su uso a menos que sea estrictamente necesario.

native

native es un modificador utilizado cuando un determinado método está escrito en un lenguaje distinto a Java, normalmente C, C++ o ensamblador para mejorar el rendimiento. La forma más común de implementar estos métodos es utilizar JNI (Java Native Interface).

transient

Utilizado para indicar que los atributos de un objeto no son parte persistente del objeto o bien que estos no deben guardarse y restaurarse utilizando el mecanismo de serialización estándar.

volatile y synchronized

volatile es, junto con synchronized, uno de los mecanismos de sincronización básicos de Java.

Se utiliza este modificador sobre los atributos de los objetos para indicar al compilador que es posible que dicho atributo vaya a ser modificado por varios threads de forma simultanea y asíncrona, y que no queremos guardar una copia local del valor para cada thread a modo de caché, sino que queremos que los valores de todos los threads estén sincronizados en todo momento, asegurando así la visibilidad del valor actualizado a costa de un pequeño impacto en el rendimiento.

volatile es más simple y más sencillo que synchronized, lo que implica también un mejor rendimiento. Sin embargo volatile, a diferencia de synchronized, no proporciona atomicidad, lo que puede hacer que sea más complicado de utilizar.

Una operación como el incremento, por ejemplo, no es atómica. El operador de incremento se divide en realidad en 3 instrucciones distintas (primero se lee la variable, después se incrementa, y por último se actualiza el valor) por lo que algo como lo siguiente podría causarnos problemas a pesar de que la variable sea volatile:

volatile int contador;

public void aumentar() {
  contador++;
}

En caso de que necesitemos atomicidad podemos recurrir a synchronized o a cosas más avanzadas, como las clases del API java.util.concurrent de Java 5.

synchronized se diferencia de volatile entre otras cosas en que este modificador se utiliza sobre bloques de código y métodos, y no sobre variables. Al utilizar synchronized sobre un bloque se añade entre paréntesis una referencia a un objeto que utilizaremos a modo de lock.

int contador;

public void aumentar() {
  synchronized(this) {
    contador++;
  }
}
int contador;

public void synchronized aumentar() {
  contador++;
}

abstract

Un viejo conocido para la mayoría de los programadores Java. La palabra clave abstract indica que no se provee una implementación para un cierto método, sino que la implementación vendrá dada por las clases que extiendan la clase actual. Una clase que tenga uno o más métodos abstract debe declararse como abstract a su vez.

final

Indica que una variable, método o clase no se va a modificar, lo cuál puede ser útil para añadir más semántica, por cuestiones de rendimiento, y para detectar errores.

Si una variable se marca como final, no se podrá asignar un nuevo valor a la variable. Si una clase se marca como final, no se podrá extender la clase. Si es un método el que se declara como final, no se podrá sobreescribir.

Algo muy a tener en cuenta a la hora de utilizar este modificador es que si es un objeto lo que hemos marcado como final, esto no nos impedirá modificar el objeto en sí, sino tan sólo usar el operador de asignación para cambiar la referencia. Por lo tanto el siguiente código no funcionaría:

public class Ejemplo {
  public static void main(String[] args) {
    final String cadena = "Hola";
    cadena = new String("Adios");
  }
}

pero sin embargo, este si:

public class Ejemplo {
  public static void main(String[] args) {
    final String cadena = "Hola";
    cadena.concat(" mundo");
  }
}

Una variable con modificadores static y final sería lo más cercano en Java a las constantes de otros lenguajes de programación.



Comentarios
  1. Hola¡¡¡
    me gustaria que comprobases la tabla de correspondencias con los modificares de acceso y desde dónde se puede acceder a la variable, ya que en mi opinión no está claro el criterio que sigues.(¿qué indica la X?)

    P.e.: el acceso a public será desde todos los elementos (¿porqué marcas una X en todas?) sin embargo entiendo que private es accesible sólo desde la propia clase (y marcas una X en desde otro paquete).

    Un saludo

    Responder

    • memo1289

      La tabla esta extremadamente correcta!!
      Pon atencion para que le entiendas, la ‘x’ quiere decir que desde el punto(titulo de la columna) es accesible por otra clase

      Responder

    • edy

      en mi opinion ese no es el private ese el protected por que el private esta bien

      Responder

  2. Después de observar la tabla, creo que has transpuesto las X, porque si cambias filas por columnas sólo en las X, obtienes como es… o eso creo…

    un saludo

    Responder

  3. @NeoMorfeo pues si, se me han movido las X 😛 Ahora lo edito.

    Responder

  4. Seria bueno una tabla con los modificadores que acepta cada objeto, por ejemplo que una variable no puede ser abstract pero que un metodo y una clase si. O que un metodo no puede ser abstract y final a la vez

    Responder

    • Lms76

      Compañero para el caso de tu cuestión, si la clase es abstract por concepto no puede ser final. Considero que hacer la tabla mezclando cosas de concepto se haría muy complejo para interpretar. También para el caso que mencionas de que si las variables pueden ser abstract, por concepto se sabe que no pues lo abstract no existe en realidad, no se instancia, no es objeto, mientras que con una variable indicas de facto que ya existe con un tipo, ya tienes un espacio en memoria para ella. Con lo abstract tienes el espacio pero no una instancia, ni una clase que se pueda instanciar. Saludos.

      Responder

  5. Muchas gracias Zootropo, es un excelente artículo, no sólo para quienes quieren aprender java sino para quienes ya lo saben, no hay que negar que esto de los modificadores siempre da su guerra.

    Saludos.

    Responder

  6. Buena explicación, la tabla de los permisos de acceso perfecta 😉

    Responder

  7. Ufff que bueno! Este artículo me ha venido como anillo al dedo! 😀
    Como siempre: muy bueno!

    Responder

  8. Muy bueno el artículo, como siempre muy currado 😉
    Además por motivos del trabajo parece que estamos siguiendo la misma trayectoria, llevaba ya unos años trabajando con python y ahora me ha tocado meterme con java.
    Saludos.

    Responder

  9. METABOLIC UTROPIC DAWN

    me gusta este documento ya que los madificadores dan mas guerra que hitler y siempre hay que saberse un truquito o dos .
    gracias

    Responder

  10. […] Ambos lenguajes tienen en común varios modificadores. […]

    Responder

  11. Mati

    como es la relacion de synchronized con

    Lock(ReentrantLock) y Condition

    Responder

  12. Karla

    Me sirvio mucho la informacion de el Modificador Static… GRACIAS

    Responder

  13. […] Mas información: Mundo Geek – Modificadores en Java […]

    Responder

  14. Que articulo ESPECTACULAR, bien resumido y bien compacto, contiene todos los tópicos relacionados con los modificadores.

    Estaba justo buscando algo asi por que la mayoria que encontré estaban en ingles.

    Gracias

    Responder

  15. Paolón

    Buen artículo, me sirvió muchísimo =) muchas gracias

    Responder

  16. kz2024

    Gracias! aunque esta muy resumido dice cosas que muchos autores no logran explicar en varias decenas de paginas…

    Muy bien explicado, sobre todo el tema de los static.

    Agradecido…

    Responder

  17. power

    genial

    Responder

  18. edwin

    muchas gracias muy bien explicado

    Responder

  19. hoña solo queria decir que los modificadores de acceso son private ,(default), protected, public
    los demas son modificadores de clase lo cual mno es lo mismo

    Responder

  20. Diego

    uf de lujo, no sabia que existía, el modificador native en java, buen dato
    Gracias

    Responder

  21. tan

    Muy Bueno.

    Seria muy interesante que comentaras de las palabras reservadas en java, ademas de la que
    aun no están en uso como “cons”.

    Responder

  22. Marcos Aybar

    Hola. Para mi se ve muy bien explicado este tema, por lo cual estoy conforme y entendido sobre este tema. Muchas gracias

    Responder

  23. Daniel

    Hola soy nuevo progrando y no entiendo bien acerca de el modificador abstract y su uso podrian dar algun ejempo o explicar mas de antemano gracias

    Responder

  24. Ale

    Muy buen post, gracias

    Responder

  25. […] actividades en Android son clases públicas que heredan de la clase base android.app.Activity. En este caso en específico declaramos un botón […]

    Responder

  26. […] primera columna nos indicará el tipo de atributo y los modificadores de acceso del […]

    Responder

  27. Anónimo

    gracias

    Responder

  28. Anónimo

    cómo se accedería a un atributo private de una clase desde otra clase del mismo paquete?

    Responder

    • Juan

      Respuesta corta: no se puede
      Respuesta larga: Tienes que implementar un método (los llamados getter) en la clase del atributo privado al que quieres acceder. Este método es public y devolverá el atributo en cuestión (al estar en esa clase, si puede acceder).
      Respuesta geek: Puedes usar reflection y convertir el atributo en accesible.

      Responder

  29. juanelo

    k buena informacion me resolvio mis dudas sobre algunos tema de java …-gracias–///deverian subir mas informacion clara y concreta—-komo esta XD….+++++ESPERO K ENCUENTREN INFORMACION K LES AYUDE A SU FORMACIÓN…

    Responder

  30. Adansky

    Esta muy clara la explicación. Gracias..

    Responder

  31. Andres Lopez

    Super, me ayudo para aclarar algunas cosas!! gracias

    Responder

  32. Daniel

    muchas gracias por compartir esta información me sirvió de mucho

    Responder

  33. Daniel Rosa

    Fantástico resumen. Felicitaciones.

    Responder

  34. Diego Armando( Perú)

    Muy bien, me sirvió de mucho es una explicación excelente gracias.

    Responder

  35. federico

    Genial, visite 100 paginas sobre este tema ,y fue el que mas claro me lo dejo
    lo tenes en pdf? gracias

    Responder

  36. Muy bueno el articulo

    Responder

  37. carlos Dominguez

    Muy bueno (y), he refrescado algunos temas olvidados xD.

    Responder

  38. Danny Mencos

    Buenísimo. Me quedo perfectamente claro!

    Responder

  39. Oe esta informacion es me fue de mucha ayuda grias al de la pagina 😀

    Responder

  40. […] te acabo de explicar. La razón es que no queremos sustituir cuatros variables locales por cuatro propiedades privadas sino hacerlo solo por […]

    Responder

  41. Anónimo

    muy buena esta imformacion, me fue de gran ayuda para entender el tema de los niveles de acceso en java, gracias

    Responder

  42. […] El término  public es un modificador de acceso y define a esta clase como pública, siendo accesible por tanto por cualquier otra clase. Por defecto, si no incluímos ningún modificador (default), solo sería accesible por clases que están incluídas en su paquete. Hay otros dos modificadores de acceso, que al igual que los anteriores, también son aplicables a los métodos y a los atributos: protected (similar a default aunque permite heredar a una subclase que no está en el paquete ) y private (si queremos que los  métodos o atributos sean solo accesibles dentro de la clase). Si quieres saber más, puedes consultar este artículo sobre modificadores Java. […]

    Responder

  43. Pablo Elizondo

    Hola, me llamo Pablo.
    Me resultó interesante 🙂 pero no entendí 🙁

    Responder

Deja un comentario