Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación METODOS, SOBRECARGA Y CONSTRUCTORES METODOS Los métodos son funciones de una clase. Generalmente los métodos se dividen en aquellos que se usan internamente en la clase, llamados métodos privados (private), los que se usan fuera de la clase, llamados métodos públicos (public) y los que son usados por la clase y sus derivadas, llamados métodos protegidos (protected). Los métodos privados son, generalmente, llamados en el interior del objeto por otras partes del mismo. Java soporta dos tipos de métodos: métodos de clase y métodos de instancia. Los métodos de instancia, son invocados en objetos (es decir, los objetos son instancias de una clase). Los métodos de clase, por otro lado, son invocados en una clase. Por ejemplo, la clase java.lang.Math tiene un método de clase llamado sqrt que calcula una raíz cuadrada, y se puede usar como sigue (no es necesario un objeto): public class app { public static void main(String[] args) { double value = 4, sqrt; sqrt = iath.sqrt(value); System.out .println( "La raíz cuadrada de " + value + " = "+ sqrt); } } Esto es lo que se puede ver cuando se ejecuta el código: C:\>java app La raíz cuadrada de 4.0 = 2.0 Los métodos son funciones que pueden ser llamadas dentro de la clase o por otras clases. La implementación de un método consta de dos partes, una declaración y un cuerpo. La declaración en Java de un método se puede expresar esquemáticamente como: tipoRetorno nombreMetodo( [lista_de_argumentos] ) { cuerpoMetodo } Los métodos pueden tener numerosos atributos a la hora de declararlos, incluyendo el control de acceso, si es estático o no estático, etc. La sintaxis utilizada para hacer que un método sea estático y su interpretación, es semejante en Java y en C++. Sin embargo, la sintaxis utilizada para establecer el control de acceso y su interpretación, es muy diferente en Java y en C++. Docente: Ing. Pedro Beltrán Canessa Ronceros ~1~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación La lista de argumentos es opcional, tanto en Java como en C++, y en los dos casos puede limitarse a su mínima expresión consistente en dos paréntesis, sin parámetro alguno en su interior. Opcionalmente, C++ permite utilizar la palabra void para indicar que la lista de argumentos está vacía, en Java no se usa. Los parámetros, o argumentos, se utilizan para pasar información al cuerpo del método. La sintaxis de la declaración completa de un método es la que se muestra a continuación con los items opcionales en itálica y los items requeridos en negrilla: especificadorAcceso static abstract final native synchronized tipoRetorno nombreMetodo( lista_de_argumentos ) throws listaExcepciones especificadorAcceso, determina si otros objetos pueden acceder al método y cómo pueden hacerlo. Está soportado en Java y en C++, pero la sintaxis e interpretación es considerablemente diferente. static, indica que los métodos pueden ser accedidos sin necesidad de instanciar un objeto del tipo que determina la clase. C++ y Java son similares en el soporte de esta característica. abstract, indica que el método no está definido en la clase, sino que se encuentra declarado ahí para ser definido en una subclase (sobreescrito). C++ también soporta esta capacidad con una sintaxis diferente a Java, pero con similar interpretación. final, evita que un método pueda ser sobreescrito. native, son métodos escritos es otro lenguaje. Java soporta actualmente C y C++. synchronized, se usa en el soporte de multithreading. lista_de_argumentos, es la lista opcional de parámentros que se pueden pasar al método throws listaExcepciones, indica las excepciones que puede generar y manipular el método. Valor de Retorno de un Método En Java es imprescindible que a la hora de la declaración de un método, se indique el tipo de dato que ha de devolver. Si no devuelve ningún valor, se indicará el tipo void como retorno. Todos los tipos primitivos en Java se devuelven por valor y todos los objetos se devuelven por referencia. El retorno de la referencia a un objeto en Java es similar a devolver un puntero a un objeto situado en memoria dinámica en C++, excepto que la sintaxis es mucho más simple en Java, en donde el ítem que se devuelve es la dirección de la posición en memoria dinámica donde se encuentra almacenado el objeto. Para devolver un valor se utiliza la palabra clave return. La palabra clave return va seguida de una expresión que será evaluada para saber el valor de retorno. Esta expresión puede ser compleja o puede ser simplemente el nombre de un objeto, una variable de tipo primitivo o una constante. El ejemplo siguiente ilustra el retorno por valor y por referencia. // Un objeto de esta clase será devuelto por referencia class miClase { int varInstancia = 10; } Docente: Ing. Pedro Beltrán Canessa Ronceros ~2~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación Si un programa Java devuelve una referencia a un objeto y esa referencia no es asignada a ninguna variable, o utilizada en una expresión, el objeto se marca inmediatamente para que el reciclador de memoria en su siguiente ejecución devuelve la memoria ocupada por el objeto al sistema, asumiendo que la dirección no se encuentra ya almacenada en ninguna otra variable. Tanto en Java como en C++ el tipo del valor de retorno debe coincidir con el tipo de retorno que se ha indicado en la declaración del método; aunque en Java, el tipo actual de retorno puede ser una subclase del tipo que se ha indicado en la declaración del método, lo cual no se permite en C++. En Java esto es posible porque todas las clases heredan desde un objeto raíz común a todos ellos: Object. En general, se permite almacenar una referencia a un objeto en una variable de referencia que sea una superclase de ese objeto. También se puede utilizar un interfaz como tipo de retorno, en cuyo caso, el objeto retornado debe implementar dicho interfaz. NOMBRE DEL MÉTODO (SOBRECARGA) El nombre del método puede ser cualquier identificador legal en Java. Java soporta el concepto de sobrecarga de métodos, es decir, permite que dos métodos compartan el mismo nombre pero con diferente lista de argumentos, de forma que el compilador pueda diferenciar claramente cuando se invoca a uno o a otro, en función de los parámetros que se utilicen en la llamada al método. El siguiente fragmento de código muestra una clase Java con cuatro métodos sobrecargados, el último no es legal porque tiene el mismo nombre y lista de argumentos que otro previamente declarado: class MiClase { ... void miMetodo( int x,int y ) { . . . } void miMetodo( int x ) { . . . } void miMetodo( int x,float y ) { . . . } // void miMetodo( int a,float b ) { . . . } // no válido } Todo lenguaje de programación orientado a objetos debe soportar las características de encapsulación, herencia y polimorfismo. La sobrecarga de métodos es considerada por algunos autores como polimorfismo en tiempo de compilación. En Java, los métodos sobrecargados siempre deben devolver el mismo tipo. MÉTODOS DE INSTANCIA Cuando se incluye un método en una definición de una clase Java sin utilizar la palabra clave static, estamos generando un método de instancia. Aunque cada objeto de la clase no contiene su propia copia de un método de instancia (no existen múltiples copias del método en memoria), el resultado final es como si fuese así, como si cada objeto dispusiese de su propia copia del método. Docente: Ing. Pedro Beltrán Canessa Ronceros ~3~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación Cuando se invoca un método de instancia a través de un objeto determinado, si este método referencia a variables de instancia de la clase, en realidad se están referenciando variables de instancia específicas del objeto específico que se está invocando. La llamada a los métodos de instancia en Java se realiza utilizando el nombre del objeto, el operador punto y el nombre del método. miObjeto.miMetodoDeInstancia(); Los métodos de instancia tienen acceso tanto a las variables de instancia como a las variables de clase, tanto en Java como en C++. MÉTODOS ESTÁTICOS Cuando una función es incluida en una definición de clase C++, o un método e incluso en una definición de una clase Java, y se utiliza la palabra static, se obtiene un método estático o método de clase. Lo más significativo de los métodos de clase es que pueden ser invocados sin necesidad de que haya que instanciar ningún objeto de la clase. En Java se puede invocar un método de clase utilizando el nombre de la clase, el operador punto y el nombre del método. MiClase.miMetodoDeClase(); En Java, los métodos de clase operan solamente como variables de clase; no tienen acceso a variables de instancia de la clase, a no ser que se cree un nuevo objeto y se acceda a las variables de instancia a través de ese objeto. Si se observa el siguiente trozo de código de ejemplo: class Documento extends Pagina { static int version = 10; int numero_de_capitulos; static void annade_un_capitulo() { numero_de_capitulos++; // esto no funciona } static void modifica_version( int i ) { version++; // esto si funciona } } la modificación de la variable numero_de_capitulos no funciona porque se está violando una de las reglas de acceso al intentar acceder desde un método estático a una variable no estática. Todas las clases que se derivan, cuando se declaran estáticas, comparten la misma página de variables; es decir, todos los objetos que se generen comparten la misma zona de memoria. Los métodos estáticos se usan para acceder solamente a variables estáticas. class UnaClase { int var; Docente: Ing. Pedro Beltrán Canessa Ronceros ~4~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación UnaClase() { var = 5; } unMetodo() { var += 5; } } En el código anterior, si se llama al método unMetodo() a través de un puntero a función, no se podría acceder a var, porque al utilizar un puntero a función no se pasa implícitamente el puntero al propio objeto (this). Sin embargo, sí se podría acceder a var si fuese estática, porque siempre estaría en la misma posición de memoria para todos los objetos que se creasen de la clase UnaClase. PASO DE PARÁMETROS En C++, se puede declarar un método en una clase y definirlo luego dentro de la clase (bajo ciertas condiciones) o definirlo fuera de la clase. A la hora de declararlo, es necesario indicar el tipo de argumentos que necesita, pero no se requiere indicar sus nombres (aunque pueda hacerse). A la hora de definir el método sí tiene que indicarse el nombre de los argumentos que necesita el método. En Java, todos los métodos deben estar declarados y definidos dentro de la clase, y hay que indicar el tipo y nombre de los argumentos o parámetros que acepta. Los argumentos son como variables locales declaradas en el cuerpo del método que están inicializadas al valor que se pasa como parámetro en la invocación del método. En Java, todos los argumentos de tipos primitivos deben pasarse por valor, mientras que los objetos deben pasarse por referencia. Cuando se pasa un objeto por referencia, se está pasando la dirección de memoria en la que se encuentra almacenado el objeto. Si se modifica una variable que haya sido pasada por valor, no se modificará la variable original que se haya utilizado para invocar al método, mientras que si se modifica una variable pasada por referencia, la variable original del método de llamada se verá afectada de los cambios que se produzcan en el método al que se le ha pasado como argumento. El ejemplo siguiente ilustra el paso de parámetros de tipo primitivo y también el paso de objetos, por valor y por referencia, respectivamente. // Esta clase se usa para instanciar un objeto referencia class MiClase { int varInstancia = 100; } // Clase principal class javaejemplo { Docente: Ing. Pedro Beltrán Canessa Ronceros ~5~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación // Función para ilustrar el paso de parámetros void pasoVariables( int varPrim,MiClase varRef ) { System.out.println( "--> Entrada en la funcion pasoVariables" ); System.out.println( "Valor de la variable primitiva: "+varPrim ); System.out.println( "Valor contenido en el objeto: "+ varRef.varInstancia ); System.out.println( "-> Modificamos los valores" ); varRef.varInstancia = 101; varPrim = 201; System.out.println( "--> Todavia en la funcion pasoVariables" ); System.out.println( "Valor de la variable primitiva: "+varPrim ); System.out.println( "Valor contenido en el objeto: "+ varRef.varInstancia ); } public static void main( String args[] ) { // Instanciamos un objeto para acceder a sus métodos javaejemplo aObj = new javaejemplo(); // Instanciamos un objeto normal MiClase obj = new MiClase(); // Instanciamos una variable de tipo primitivo int varPrim = 200; System.out.println( "> Estamos en main()" ); System.out.println( "Valor de la variable primitiva: "+varPrim ); System.out.println( "Valor contenido en el objeto: "+ obj.varInstancia ); // Llamamos al método del objeto aObj.pasoVariables( varPrim,obj ); System.out.println( "> Volvemos a main()" ); System.out.println( "Valor de la variable primitiva, todavia : "+ varPrim ); System.out.println( "Valor contenido ahora en el objeto: "+ obj.varInstancia ); } } Tanto en Java como en C++, los métodos tienen acceso directo a las variables miembro de la clase. El nombre de un argumento puede tener el mismo nombre que una variable miembro de la clase. En este caso, la variable local que resulta del argumento del método, oculta a la variable miembro de la clase. Cuando se instancia un método se pasa siempre una referencia al propio objeto que ha llamado al método, es la referencia this. Docente: Ing. Pedro Beltrán Canessa Ronceros ~6~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación CONSTRUCTORES Una vez que se tiene definida la clase a partir de la cual se crearán los objetos se está en la posibilidad de instanciar los objetos requeridos. Para la clase Usuario del ejemplo anterior podemos crear un objeto de la siguiente manera: Usuario usr1; //usr1 es una variable del tipo Usuario usr1 = new Usuario(); La primera línea corresponde a la declaración del objeto, es decir, se declara una variable del tipo de objeto deseado. La segunda línea corresponde a la iniciación del objeto. El operador new El operador new crea una instancia de una clase asignando la cantidad de memoria necesaria de acuerdo al tipo de objeto. El operador new se utiliza en conjunto con un constructor. El operador new regresa una referencia a un nuevo objeto. Constructores Un constructor es un tipo específico de método que siempre tiene el mismo nombre que la clase, y que se utiliza cuando se desean crear objetos de dicha clase, es decir, se utiliza al crear e iniciar un objeto de una clase. Constructores múltiples Cuando se declara una clase en Java, se pueden declarar uno o más constructores (constructores múltiples) opcionales que realizan la iniciación cuando se instancia un objeto de dicha clase. Para la clase Usuario del ejemplo anterior no se especificó ningún constructor, sin embargo, Java proporciona un constructor por omisión que inicia las variables del objeto a sus valores predeterminados. Ej. /* ProgUsuario.java */ class ProgUsuario { public static void main(String args[]) { Usuario usr1, usr2; /* Se declaran dos objetos de la clase Usuario */ boolean si_no; Docente: Ing. Pedro Beltrán Canessa Ronceros ~7~ Universidad Los Ángeles de Chimbote usr1 = new Usuario(); Curso: Técnicas de Programación /* Se utiliza el constructor por omisión */ si_no = usr1 instanceof Usuario; if(si_no == true) System.out.println("\nEl objeto usr1 SI es instancia de Usuario."); else System.out.println("\nEl objeto usr1 NO es instancia de Usuario."); usr2 = usr1; /* usr1 y usr2 son el mismo objeto */ si_no = usr2 instanceof Usuario; if(si_no == true) System.out.println("\nEl objeto usr2 SI es instancia de Usuario."); else System.out.println("\nEl objeto usr2 NO es instancia de Usuario."); } } Características de los Constructores 1. Un constructor, tiene el mismo nombre de la clase a la cual pertenece. 2. No puede ser Heredado. 3. No retorna ningún valor (Ni void), por lo cual no debe especificarse ningún tipo de dato. 4. Debe declararse como public, sólo en casos realmente extraordinarios será de otro tipo. Supongamos una clase llamada Datos public class Datos { //declaracion de atributos public Datos();//constructor sin parámetros public Datos(int Edad) {//Constructor con parámetros EdadM=Edad; } } Docente: Ing. Pedro Beltrán Canessa Ronceros ~8~ Universidad Los Ángeles de Chimbote Curso: Técnicas de Programación Ejemplo Se Desea crear un objeto del tipo Coordenadas, que indique, la posición de un punto en el plano cartesiano, y permita calcular la distancia existente con otro punto, además del punto medio entre ellos. 1 /*Archivo Coordenadas.java*/ 2 3 public class Coordenadas { 4 private int x,y;//Atributos 5 public Coordenadas (int x1 , int y1)//constructor 6 { 7 //asignamos esos valores 8 x=x1; 9 y=y1; 10 } 11 public double Distancia (int x1, int y1) 12 { 13 //este método recibe como parámetros 14 //las coordenadas del segundo punto 15 double D; 16 D=Math.sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1)); 17 return D;//Retornamops el valor de la distancia 18 } 19 public void Pmedio(int x1, int y1) 20 { 21 double p1, p2; 22 p1=(x+x1)/2; 23 p2=(y+y1)/2; 24 System.out.println("El puntomedio es: "+p1+","+p2); 25 } 26 } 1 /*Archivo UsaCoordenadas.java*/ 2 public class UsaCoordenadas { 3 public static void main (String args []){ 4 Coordenadas P=new Coordenadas (10,20); 5 //calculamos la Distancia: 6 System.out.println("La Distancia es: "+P.Distancia(5,6)); 7 //Punto Medio 8 P.Pmedio(5,6); 9 } 10 } Explicación: Un método, si va a devolver algún valor, éste debe especificarse cuando se hace la definición del mismo, para el caso, el método Distancia, devuelve el valor de la distancia, es por ello que lo especificamos como public double. Además que, cuando realizamos la llamada de ese método, es en ese preciso lugar que aparecerá el valor que devuelve. Por otra parte, los atributos, son de acceso privado, lo cual implica que, sólo podemos acceder a ellos, en la clase Coordenadas. Docente: Ing. Pedro Beltrán Canessa Ronceros ~9~