sintesis

java

Códigos disponibles en git

¿Por qué?

contexto
Lenguajes Compilados Lenguajes Interpretados
compilador
interprete
  • Máquina X

>compiladorXA prog.ext
>prog.exe
  • Máquina Y

>prog.exe
ERROR!!!
  • Máquina X

>interpreteXA prog.ext
  • Máquina Y

>interpreteYA prog.ext
  • soluciones sin portabilidad y rápida ejecución (sin análisis)

  • soluciones con portabilidad y lenta ejecución (con análisis)

¿Qué?

Plataforma de Desarrollo de Sun MicroSystems y Oracle
  • Biblioteca estándar, Application Programming Interface (API)

    • Conjunto de utilidades predefinidas que permiten desarrollar aplicaciones y comunicarse con el sistema operativo

    • Ej. Gestión de Ficheros, Conexiones de Red, Estructuras de Datos, Expresiones Regulares, Bases de Datos

  • Intérprete, Java Virtual Machine, (JVM)

    • Programa que ejecuta programas escritos en Java

    • Existe una máquina virtual por sistema operativo y procesador

    • Permite que el mismo programa Java pueda ejecutarse en cualquier sistema operativo

plataforma0

>javac prog.java
>java prog.class
  • compilación Just in Time: compila el bytecode a código nativo en tiempo de ejecución y luego ejecuta, evitando el re-análisis del bytescode cada vez

plataforma1
plataforma2
JavaFeatures
HistoryOfJava

¿Para qué?

  • Java Standard Edition (Java SE)

    • versión usada en ordenadores personales

  • Java Enterprise Edition (Java EE)

    • Define un conjunto de librerías para el desarrollo de aplicaciones web

    • Necesita Java SE para ejecutarse

  • Java Micro Edition (Java ME)

    • Entorno para desarrollar aplicaciones en dispositivos con recursos limitados como dispositivos móviles, software empotrado en electrodomésticos, etc

plataforma4

¿Cómo?

Multi-paradigma Elementos de Programación Capacitación

Programación Imperativa

  • la gestión de datos con valores de tipos primitivos

  • evaluacion de expresiones de su jerarquía de operadores

  • la sentencia de asignación, entrada y salida

  • "pequeñísimo" programa secuencial

Programación Estructurada

  • las sentencias secuencial, alternativas e iterativas sobre datos primitivos

  • y sobre datos compuestos en colecciones homogéneas, array

  • cualquier "pequeño" programa

Programación basada en Objetos

  • la organización/estructuración/modularización del código con clases, nueva unidad (compuesto de datos y funciones)

  • "mediano/gran" programa organizado en objetos

Programación Orientada a Objetos

  • gestionar las relaciones de herencia para la clasificación

  • "mediano/gran" programa organizado en objetos

Programación Modular

  • la organización/estructuración/modularización del código con paquetes, nueva unidad (compuesto de clases, …​)

  • Exportación e importación de paquetes

  • "grandísimo" programa organizado en módulos

Programación con Excepciones

  • gestión de fallos, defecto y errores lógicos o excepcionales frente a las aserciones

  • sentencia try/catch/finally

  • programa con tratamiento de errores excepcionales

Programación Parametrizada

  • Plantilla y encarnación

  • programa con clases parametrizadas en tipos

Programación Recursiva

  • Listas, Árboles, …​

  • programa con clases recursivas

Programación Funcional

  • Funciones lambda, flujos, Optional, …​

  • programa con inmutabilidad

Programación Concurrente

  • Threads, Fibras, CompletableFuture, …​

  • programa con varios flujos de ejecución

Programación Reactiva

  • Reactor, …​

  • programa asíncrono no bloqueante con flujos de eventos

Programa

  • Un programa se compone de paquetes que se componen de otros paquetes y clases, bajo el paradigma de la programación modular

    • cada clase reúne atributos presentes en todas sus instancias, que pueden ser de tipo primitivo o de alguna clase junto con sus métodos

    • cada método reúne parámetros y un conjunto de sentencias:

    • crear dato, sentencias de declaración de variables/constantes

    • modificar datos, sentencias de asignación, entrada y salida

    • eliminar datos, asociados a los ámbitos de los métodos

    • consultar datos, mediante referencias desde las expresiones

  • Las sentencias contienen expresiones que pueden ser

    • expresiones simples mediante la mención de los datos o literales

    • expresiones compuestas mediante la combinación de operadores

  • Las sentencias pueden ser compuestas, bajo el paradigma de la programación estructurada

    • sentencia secuencial, para la creación de ámbitos anidados en el ámbito del progrma,

    • sentencia alternativa, para alternar la ejecución de sentencias,

    • sentencia iterativa, para repetir la ejecución de sentencias.

    • sentencias con excepciones, para elevar, capturalas y delegarlas.

  • Los datos, constantes o variables, pueden ser de tipo

    • primitivo, para átomos de información sin propiedades e inmutables

    • array, para colecciones compuestas de datos homogéneas

    • objetos, para colecciones compuestas de datos heterogéneas bajo el paradigma de la programación orientada a objetos

diagramaItinerario
Programa java
  • Sintaxis:

    • <sentencia> ::= <sentenciaSalida>

    • <sentenciaSalida> ::= console.writeln ( [ <expresion> ] ) ;

    • <expresion> ::= <literal>

    • <literal> ::= <cadenaCaracteres>

  • Semántica:

    • Se ejecutan secuencialmente de arriba a abajo todas las sentencias

  • Advertencia:

    • Las ocho primeras líneas y dos últimas se explilcarán en los sucesivos apartados de este documento!!!

    • Todos los códigos deben ir acompañandos en carpeta "utils" el fichero: utils/Console.java

package es.usantatecla.a0_itinerario.a0_programa.v0;

class App {
    
    public static void main(String[] args) {
        Console console = new Console();
        console.writeln("Hola Mundo !!!");
        console.writeln();
        console.writeln("Adios Mundo !!!");
    }
}
Comentarios java
  • Sintaxis:

    • <comnetario> ::= // <caracter> * <saltoLinea>

    • <comnetario> ::= / * <caracter> /

    • Válidos entre la secuencia de valores, operadores, identificadores, …​ nunca dentro de éstos!!!

    • Invalidos si anidan dentro de comentarios del mismo o distinto tipo

  • Semántica:

    • No se ejecutan los caracteres internos al comentraio

    • No recomendados, clean code

package es.usantatecla.a0_itinerario.a0_programa.v1;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    console.writeln(/* aquí es raro, raro, ...*/"Hola Mundo !!!");
    // gestorIO.writeln(); Dead Code!!!
    // típico comentario innecesario
    console.writeln("Adios Mundo !!!");
  }
}

Programación Imperativa

Tipos Primitivos Sentencias simples Operadores Expresiones

Tipo numericos, valores y operadores aritméticos unarios y binarios

Salida de datos por consola

Operadores de de bits, unario y binarios

Precedencia y asociatividad de operadores

Tipo char y literales String, valores y operadores de concatenación

Entrada de datos por consola

Operadores y conversión de tipos

Operador paréntesis

Tipo boolean, valores y operadores lógicos unario y binarios

Sentencias de declaración de variables y constantes

Operadores de ternario

Operadores relacionales, operadores de igualdad, desigualdad y ordenacion

Sentencia de asignación

Operadores con efectos laterales: acumulación e incremento/decremente y coma

Tipos Primitivos

tiposPrimitivos
  • Un Tipo es un conjunto de valores que comparten un conjunto de operadores:

    • Los valores de tipo numéricos corresponden con los números reales/decimales y enteros

    • Las valores de tipo char y String corresponden respectivamente con un único caracter (cualquier letra mayúscula o minúscula, dígito, signo de puntuación, caracter especial, …​) y con cualquier secuencia de caracteres (cualquier frase, párrafo, texto, …​)

    • Los valores de tipo boolean corresponden con la dualidad, sólo dos posibles valores, cierto y falso

  • Operador es una función pura matemática (correspondencia: a tal entrada de datos, corresponde tal salida de datos) con una notación simbólica:

    • prefija (<operador> <expresion>): -x

    • infija (<exprsión> <operador> <expresion>): x+1

    • sufija (<expresión> <operador>): x!

    • La notación nominal: funcion([<parámetro>, <parametro>, …​ ]) es propuesta por Euler para evitar la confusión de símbolos arrastrados desde los sumerios: +,-,…​,!,%,…​, gradiente, derivada, integral, sumatorio, …​

  • Ciertos operadores (asignación, incremento y decremento) no son funciones puras puesto que tienen efectos laterales

Tipos numéricos

Literales
  • Sintaxis:

    • <literal> ::= <valorNumerico>

    • <valorNumerico> ::= <parteEntera> [ <parteDecimal> ] [ <exponente> ]

    • <parteEntera> ::= [ 0b | 0x ] <signo> [0.9] +

    • <parteDecimal> ::= .[0.9] +

    • <exponente> ::= e <signo> [0-9] +

    • <signo> ::= [ + | - ]

  • Semántica:

    • prefijos 0b y 0x son respectivamente para notación binaria y hexadecimal

    • todos los literales enteros serán de tipo int

    • todos los literales con decimales o notación científica serán de tipo double

class App {

  public static void main(String[] args) {
    Console console = new Console();
    console.writeln(356); // 356
    console.writeln(-66); // -66
    console.writeln(34.45); // 34.45
    console.writeln(-2.343e-5); // -2.343E-5
    console.writeln(0); // 0
    console.writeln(-0); // 0
    console.writeln(-024); // -20
    console.writeln(0xA4); // 164
  }
}
Operadores unarios
  • Sintaxis:

    • <expresion> ::= <operadorAritmeticoUnario> <expresion>

    • <operadorAritmeticoUnario ::= - | +

  • Semántica:

    • operan sobre valores numéricos del mismo tipo, y devuelven un valor del tipo de los operandos (menos byte, short y char, que devuelven int)

      • +, identidad, devuelve el mismo valor numérico dado;

      • -, opuesto, delvuelve el valor con cambio de signo respecto al valor numérico dado

class App {

  public static void main(String[] args) {
    Console console = new Console();
    console.writeln(+ -5); // -5
    console.writeln(- -5); // 5
  }
}
Operadores binarios
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorAritmetico> <expresion>

    • <operadorAritmetico> ::= - | * | / | %

  • Semántica:

    • operan sobre valores numéricos del mismo tipo, y devuelven un valor del tipo de los operandos (menos byte, short y char, que devuelven int)

      • +, suma

      • -, resta

      • *, multiplicación

      • /, división

      • %, módulo resto

class App {

  public static void main(String[] args) {
    Console console = new Console();
    console.writeln(4 + 5); // 9
    console.writeln(4 - 5); // -1
    console.writeln(4 * 5); // 20
    console.writeln(4 / 5); // 0.8
    console.writeln(4 % 5); // 4

    //console.writeln(4 / 0); // Exception
    //console.writeln(4 % 0); // Exception

    console.writeln(0.1e-7 + 1e7); // 1.000000000000001E7
    console.writeln(0.1e-8 + 1e8); // 1.0E8
    console.writeln(0.1 + 0.2); // 0.30000000000000004
  }
}

Tipo boolean

Valores de tipo boolean
boolean java
  • Sintaxis:

    • <literal> ::= <valorLogico>

    • <valorLogico> ::= true | false

  • Semántica:

    • correspondientes con cierto y false respectivamente

package es.usantatecla.a0_itinerario.a1_imperativa. a1_tipos.a3_boolean.a1_valores;

public class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(true); // true
        console.writeln(false); // false
    }
}
Operadores unarios
operador unario prefijo java
  • Sintaxis:

    • <expresion> ::= ! <expresion>

  • Semántica:

    • !, negación lógica, el opuesto

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a3_boolean.a2_unarios;

public class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(!false); // true
        console.writeln(!true); // false
    }
}
Operadores binarios
operadores binarios infijos java
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorBinarioLogico> <expresion>

    • <operadorBinarioLogico> ::= && | ||

  • Semántica:

    • &&, y-lógico: devuelve la evaluación de la primera expresión, no true, cuando ambos operandos son evalúan a cierto

    • || , o-lógico: devuelve la evaluación de la primera expresión, no true cuando es cierto o, caso contrario, la evaluación de la segunda expresión cuando es cierta

    • false en casos contrarios

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a3_boolean.a3_binarios;

public class App {

    public static void main(String[] args) {
        Console console = new Console();

        console.writeln(false && false); // false
        console.writeln(false && true); // false
        console.writeln(true && false); // false
        console.writeln(true && true); // true

        console.writeln(false || false); // false
        console.writeln(false || true); // true
        console.writeln(true || false); // true
        console.writeln(true || true); // true
    }

}

Tipo char

Literales de tipo char
char java
  • <literal> ::= <valorCaracter>

  • <valorCaracter> ::= ' <caracter> ' | ' \ <caracter> '

    • <caracter> son los caracteres imprimibles del código ASCII (espacio, letras, dígitos, símbolos de puntuación, …​)

    • los caracteres "escapados" son aquellos que no son imprimibles (salto de línea, …​) o con sobrecarga de significados (apostrofe para comienzo de cadena, …​) que deben precederse del caracter escape: '\n', '\t', …​ '\"', '\'', '\"' y '\\',

      • \uXXXX para caracteres de UTF-16 de Unicode

        • donde X será un valor hexadecimal: [0-9AF]

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a4_char.a1_valores;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln('a'); // a
        console.writeln('1'); // 1
        console.writeln(' '); //  
        console.writeln('*'); // *
        console.writeln('\n'); // (salto de línea)
        console.writeln('\u3333'); // ?
    }

}

Literales String

Literales de tipo string
string java
  • <cadenaCaracteres> ::= ( " | ' ) <caracter> * ( " | ' )

    • donde

      • las comillas simples o compuestas de apertura y cierre deben ser iguales y distintas de cualquier caracter interior

      • <caracter> es

        • cualquiera caracter ASCII (espacio, letras, dígitos, símbolos de puntuación, …​)

        • excluyendo aquellos no imprimibles (salto de línea, …​) o con significado (comienzo de cadena, …​) que deben precederse del caracter escape: \n, \t, …​ \", \', \" y \\ (tabla),

        • \uXXXX para caracteres de UTF-16 de Unicode

        • \xXX para caracteres de ASCII / ISO 8859-1 (Latin-1)

        • \u{XXXXXX} para caracteres de UTF-32

        • en todos los casos anteriores, X será un valor hexadecimal: 0, …​, 9, A, …​, F

  • <cadenaCaracteres> ::= ` ( <caracter> | ${ <expresion> } ) * `

    • para plantillas literales, cadenas literales que habilitan el uso de expresiones incrustadas

    • con los mismos caracteres que las cadenas anteriores pero sin necesidad de caracter de escape para las comillas, ni saltos de línea, …​

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a2_string.a1_valores;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln("cadena de caracteres con comillas dobles"); // cadena de caracteres con comillas dobles
        console.writeln("cadena de caracteres con comillas dobles 'con comillas simples' dentro"); // cadena de caracteres con comillas dobles 'con comillas simples' dentro
        console.writeln("cadena de caracteres\ncon salto de línea y \ttabulador"); // cadena de caracteres
        // con salto de línea y    tabulador
        console.writeln("Qué \"incomodo\" usar comillas con 'quit'!!!"); // Qué "comodo" usar comillas con normalidad sin 'escaparlas'!!!
        console.writeln(""); //  
        console.writeln("1"); // 1
        console.writeln("123"); // 123
        console.writeln("TRUE."); // TRUE.
        console.writeln("false"); // false
        
        console.writeln("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"+
        "Donec rhoncus sollicitudin enim vitae tempor.\n"+
        "Nullam dui lorem, vulputate varius sapien ac, malesuada dictum metus.\n"+
        "...");
    }

}
Operador de Concatenación
Concatenación java
  • Sintaxis:

    • <expresion> ::= <expresion> + <expresion>

  • Semántica:

    • +, operador binario que, dados dos string, devuelve otra cadena de caracteres con los primeros caracteres iguales al primer string y los últimos caracteres iguales a los del segundo string

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a2_string.a2_concatenacion;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    console.writeln("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
        "Donec rhoncus sollicitudin enim vitae tempor.\n" +
        "Nullam dui lorem, vulputate varius sapien ac, malesuada dictum metus.\n" +
        "...");
    console.writeln("1" + "2" + "3" + "..."); // 123...
    console.writeln(535 + " * " + 723 + " = " + 535 * 723 + "."); // 535 * 723 = 386805.
  }
}

Operadores Relacionales

Tipo numerico
Operadores binarios infijos java
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorRelacional> <expresion>

    • <operadorRelacional> ::= ( == | != | )

  • Semántica: dados dos valores del mismo tipo numérico, devuelve un valor de tipo boolean correspondiente a la relación de cada operador según el orden de los números reales

    • ==, igualdad en valor; !=, desigualdad en valor; <, menor; , menor o igual; >, mayor; >=, mayor o igual

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a4_relacional.a2_numericos;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(5 == 5);  // true
        console.writeln(5 != 6); // true
        console.writeln(5 < 6); // true
        console.writeln(5 <= 5); // true
        console.writeln(5 > 4); // true
        console.writeln(5 >= 5); // true
    }
}
Tipo char
Operadores binarios infijos, java
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorRelacional> <expresion>

    • <operadorRelacional> ::= ( == | != )

  • Semántica: dados dos char, devuelve un valor de tipo boolean correspondiente a la relación de cada operador según la exacta igualdad de los caracteres

    • ==, igualdad en valor; !=, desigualdad en valor;

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a4_relacional.a4_char;

class App {

    public static void main(String[] args) {
        Console console = new Console();

        console.writeln('c' == 'c'); // true
        console.writeln('c' != 'C'); // true
        console.writeln(' ' != '\n'); // true  
        console.writeln('a' < 'b'); // true   
        console.writeln('a' <= 'a'); // true   
        console.writeln('a' > 'A'); // true  
        console.writeln('a' >= 'A'); // true    
    }
}
Tipo boolean
Operadores binarios infijos java
  • <expresion> ::= <expresion> <operadorRelacional> <expresion>

  • <operadorRelacional> ::= ( == | != )

    • Semántica: : dados dos valores de tipo boolean, devuelve un valor de tipo boolean correspondiente a la igualdad o no de los respectivos operadores

  • ==, igualdad en valor; !=, desigualdad en valor;

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a4_relacional.a3_boolean;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(true == true); // true
        console.writeln(true != false); // true
    }
}
Tipo string
Operadores binarios infijos, java
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorRelacional> <expresion>

    • <operadorRelacional> ::= ( == | != )

  • Semántica:

    • dados dos string, devuelve un valor de tipo boolean correspondiente a la relación de cada operador según la exacta igualdad de la secuencia de caracteres

      • ==, igualdad en valor; *!=*, desigualdad en valor;

package es.usantatecla.a0_itinerario.a1_imperativa.a1_tipos.a4_relacional.a1_string;

class App {

    public static void main(String[] args) {
        Console console = new Console();

        console.writeln("cadena" == "cadena"); // true
        console.writeln("cadena" != "cadena distinta"); // true        
    }
}

Sentencias Simples

Salida de Datos

Salida de Datos java
  • Sintáxis:

    • <sentencia> ::= console.writeln( [ <expresion> ] ) ; | console.write( <expresion> ) ;

  • Semántica:

    • Muestra por consola el valor resultado de la evaluación de la expresión

package es.usantatecla.a0_itinerario.a1_imperativa.a2_sentenciasSimples.a1_salida;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(); //
        console.write("pierDeN o gaNeN"); // pierDeN o gaNeN
        console.writeln(true); // true
        console.writeln(1); // 1
    }
}
Aplicaciones

Entrada de Datos

Entrada de datos java
  • Sintaxis:

    • <expresion> ::= console. read[red]( Byte | Short | Int | Long | Float | Double | Char | Boolean | String ) ( [ <String> ] )

  • Semántica: devuelve el valor del tipo correspondiente (numérico, carácter, lógico vs string) introducido por el usuario tras la interrumpción de la ejecución hasta que el usuario pulsa enter (introducir, no entrar!!!)

    • El parámetro opcional indica el string que se mostrará antes de la entrada de datos para guiar al usuario

package es.usantatecla.a0_itinerario.a1_imperativa.a2_sentenciasSimples.a2_entrada;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln("El siguiente es " + console.readInt("Dame un número: ") + 1);
    }
}
Aplicaciones

Sentencia de Declaración de Variable

Sentencia de Declaración de Variable java
  • Sintaxis:

    • <sentencia> ::= ( byte | short | int | long | float | double | char | String | boolean ) <identificador> [ = <expresion> ];

    • <identificador> ::= [ a - zA - Z_$ ] [ a - zA - z0 - 9_$ ]*

      • distinto de cualquier otro identificador del mismo ámbito y de cualquier palabra reservada: const, let, if, for, function, new, …​

      • estilo: camelCase: palabras yuxtapuestas con la inicial en mayúsculas a partir de la segunda palabra

  • Semántica:

    • Reserva de memoria para

      • almacenar un único valor, y posteriormente,

      • consultar su valor si ha sido inicializada o asignada previamente y

      • modificar su valor mediante la asignación del valor de la evalución de una expresión,

      • desde la línea de la declaración hasta el final del ámbito que encierra la declaración

package es.usantatecla.a0_itinerario.a1_imperativa.a2_sentenciasSimples.a3_variable;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        int identifier = 0;
        console.writeln("Valor actual ." + identifier + "."); // Valor actual .0.
        console.writeln("Valor siguiente ." + (identifier + 1) + "."); // Valor siguiente .1.
        console.writeln("Valor actual ." + identifier + "."); // Valor actual .0.
        int identifierWithoutInitialization;
        //console.writeln("." + identifierWithoutInitialization + "."); // Error
        byte code = 127;
        short age = -1000;
        long euros = 1234567890;
        float distance; // conversion
        double lighYear = 0.0234;
        char initial = 'A';
        boolean error = false;
    }
}

Palabras Reservadas

palabrasReservadas
Aplicaciones

Sentencia de Asignación

Operador de asignación java
  • Sintaxis:

    • <expresion> ::= <identificador> = <expresion> ;

  • Semántica:

    • como "sentencia", asigna/ actualiza/ "iguala", …​, set, move, :=, …​, con efecto lateral: asignando a la variable identificada a la izquierda el resultado de la evaluacíon de la expresión con restricción al tipo de la variable, lenguaje con sistema de tipos estático!!!

    • como operador, devuelve, el valor recién asignado a la variable

      • No recomendado como parte de otra expresión

package es.usantatecla.a0_itinerario.a1_imperativa.a2_sentenciasSimples.a4_asignacion;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        int x;
        int y;
        int z = -1;
        x = y = z;
        console.writeln(x); // -1
        x = 0;
        console.writeln(x); // 0
        x = x + 1;
        console.writeln(x); // 1
        console.writeln(x + 1); // 2
        console.writeln(x); // 1
        console.writeln(x = x + 1); // 2
        console.writeln(x); // 2
    }
}
Aplicaciones

Sentencia de Declaración de Constante

Sentencia de Declaración de Constante java
  • Sintaxis:

    • <sentencia> ::= final ( byte | short | int | long | float | double | char | boolean | String ) <identificador> = <expresion> ;

  • Semántica:

    • referenciable desde las expresiones del ámbito de la declaración pero no mutable!!!

package es.usantatecla.a0_itinerario.a1_imperativa.a2_sentenciasSimples.a5_constante;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        final String CONSTANT = "constante";
        console.writeln("Esto es " + CONSTANT + "!!!"); // Esto es constante
        // CONSTANT = "mutacion"; Error!!!
    }
}
Aplicaciones

Operadores

Operadores de Bits

Sintaxis java
  • Sintaxis:

    • <expresion> ::= <expresion> <operadorBit> <expresion>

    • <operadorBit> ::= & | | | ^ | ~ | << | >> | >>>

  • Semántica:

    • &, y-lógico de bits;

    • |, o-lógico de bits;

    • ^, o-lógico exclusivo de bits;

    • ~, negación de bits;

    • <<, desplaza hacia la izquierda rellenando con ceros;

    • >>, desplaza hacia la derecha rellenando con el más significativo;

    • >>>, desplaza hacia la derecha rellenando con ceros

package es.usantatecla.a0_itinerario.a1_imperativa.a3_operadores.a1_bits;

class App {
    
    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(~4); // -5
        console.writeln(4 & 8); // 0
        console.writeln(4
Aplicaciones

Operador Ternario

Operador ternario java
  • Sintaxis:

    • <expresion> ::= <expresion> ? <expresion> : <expresion>

  • Semántica:

    • devuelve

      • la evaluación del segundo argumento si la evaluación del primer argumento resulta cierto

      • o la evaluación del tercero argumento en caso contrario

package es.usantatecla.a0_itinerario.a1_imperativa.a3_operadores.a3_ternario;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(true ? "si / entonces / segundo / izquierda" 
                    : "no / en caso contrario / tercero / derecha "); // si / entonces / segundo / izquierda
        console.writeln(false ? -1 : +1); // 1
    }
}
Aplicaciones

Operadores de Acumulación

Operador de acumulación java
  • Sintaxis:

    • <sentencia> ::= <expresion> ;

    • <expresion> ::= <identificador> <operadorAcumulacion> <expresion>

    • <operadorAcumulacion> ::= += | -= | \=* | \*=* | /= | %= | &= | |= | ^= | <⇐ | >>= | >>>=

  • Semántica:

    • Abreviatura de: <identificador> = <identificador> <operador> <expresion>

    • No recomendado como parte de otra expresión, con efectos laterales, de tal forma que la evaluación de la nueva evaluación de la misma expresión arroja distintos resultados

package es.usantatecla.a0_itinerario.a1_imperativa.a3_operadores.a4_acumulador;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        int x = 234;
        console.writeln(x += 2); // 236
        console.writeln(x -= 2); // 234
        console.writeln(x *= 2); // 468
        console.writeln(x /= 2); // 234
        console.writeln(x %= 7); // 3
        console.writeln(x |= 2); // 3
        console.writeln(x &= 2); // 2
        console.writeln(x ^= 3); // 1
        console.writeln(x <<= 2); // 4
        console.writeln(x >>= 2); // 1
        console.writeln(x >>>= 2); // 0
        console.writeln(x += 1 * 5); // 5
        console.writeln(x += 1 * 5); // 10
        console.writeln(x); // 10
    }
}
Aplicaciones

Operadores de Incremento y Decremento

Operador de incremento/decremento java
  • Sintaxis:

    • <sentencia> ::= <expresion> ;

    • <expresion> ::= ( <identificador> <operadorIncrementoDecremento> | <operadorIncrementoDecremento> <identificador> )

    • <operadorIncrementoDecremento> ::= ++ | --

  • Semántica:

    • Abreviatura de: <identificador> = <identificador> <operador> ( 1 | -1 )

    • pero la expresión devuelve el valor de la variable incrementada/decrementada o o el valor previo al incremento/decremento dependiendo de si el operador es prefijo o postfijo respectivamente, en cualquier caso modifica el valor de la variable

    • No recomendado como parte de otra expresión, con efectos laterales

package es.usantatecla.a0_itinerario.a1_imperativa.a3_operadores.a5_incrementoDecremento;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        int x= 100;
        console.writeln(x); // 100
        console.writeln(x++); // 100
        console.writeln(++x); // 102
        console.writeln(x--); // 102
        console.writeln(--x); // 100
        console.writeln(- -x); // 100
        console.writeln(+ +x); // 100
        console.writeln(++x*2); // 202
        console.writeln(++x*2); // 204
        console.writeln(x++*2); // 204
        console.writeln(x); // 103
    }
}
Aplicaciones

Operador Coma

Operador coma java
  • Sintaxis:

    • <expresion> ::= <expresión> { , <expresión> } +

  • Semántica:

    • devuelve la evaluación del la última expresión; por tanto, el único sentido será disponer expresiones previas a la última por sus efectos laterales

    • Desaconsejado, excepto en sitios puntuales (p.e. sentencia for, …​)

Unresolved directive in ust4_how/ust1_imperative/ust3_operators/ust5_comma.adoc - include::../../../../../../../src/0-itinerario/1-imperativa/4-expresiones/3-compuesta/app.adoc[]

Conversión de Tipos

  • Promoción: transforman un dato de un tipo a otro con el mismo o mayor espacio en memoria para almacenar información;

  • Contracción: transforman un dato de un tipo a otro con menor espacio en memoria para almacenar información con la consecuente posible pérdida de información;

conversion
  • Conversión implícita:

    • por promoción cuando se combinan dos operandos de distinto tipo, se convierte el de menor precisión al de mayor precisión;

    • por promoción cuando se asigna un valor de un tipo de menor precisión a una variable de mayor precisión;

- Conversión explícita: java
  • Sintaxis:

    • <expresion> ::= ( <tipo> ) <expresion>

    • _<tipo> ::= byte | short | int | long | float | double | char | boolean

  • Semántica:

    • por promoción o contracción a través del operador de conversión de tipos (cast), cuyo nivel de precedencia es el de los operadores unarios;

package es.usantatecla.a0_itinerario.a1_imperativa.a3_operadores.a2_conversion;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        byte id1 = 127;
        console.writeln(id1); // 127
        id1 = (byte) 128;
        console.writeln(id1); // -128
        short id2 = id1;
        console.writeln(id2); // -128
        int units = 13;
        console.writeln(units/2); // 6
        console.writeln((float) units/2); // 6.5
    }
}

Expresiones

Precedencia y asociatividad

Expresiones java
  • Sintaxis:

    • combinación

      • de operandos (literales, identifcadores de variables y constantes)

      • y operadores (prefijos, infijos, sufijos y ternarios)

  • Semántica:

    • cuya evaluación devuelve un valor de tipo primitivo

      • un operando ambiguo, entre dos operadores, alimenta al operador de mayor nivel de precedencia

      • ante el mismo nivel de precedencia, alimenta al operador de la asociatividad establecida para ese nivel de precedencia

      • estas reglas no determinan el orden de evaluación

package es.usantatecla.a0_itinerario.a1_imperativa.a4_expresiones.a1_asociatividad;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(100/2-1); // ¿100 o 49?
        console.writeln(4>=7 && 2==4 || 5<6); // ¿false o true?
        console.writeln(100/2/2); // ¿100 o 25?
        console.writeln(1-1-1); // ¿1 o -1?
        console.writeln(5 * 4+4 * 2); // ¿80 o 28?
        console.writeln(5+4 / 4+2); // ¿1 u 8?
    }
}
tablaPrecedencia

Operador Paréntesis

Operador paréntesis java
  • Sintaxis:

    • <expresion> ::= ( <expresión> )

  • Semántica:

    • devuelve la evaluación de la expresión anidada

package es.usantatecla.a0_itinerario.a1_imperativa.a4_expresiones.a2_parentesis;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(100/(2-1)); // ¿100 o 49?
        console.writeln(4>=7 && (2==4 || 5<6)); // ¿false o true?
        console.writeln(100/(2/2)); // ¿100 o 25?
        console.writeln(1-(1-1)); // ¿1 o -1?
        console.writeln(5 * (4+4) * 2); // ¿80 o 28?
        console.writeln((5+4) / (4+2)); // ¿1 u 8?
    }
}
Aplicaciones

Programación Estructurada

Sentencias alternativas Sentencias iterativas Sentencia secuencial Arrays

Sentencias if y switch

Sentencias while, do/while, for (ni "break" ni continue)

Sentencia con ámbitos de bloque y colisión y ocultación de identificadores

Colección homogénea de datos, creación, modificaciones y consultas

Sentencias Alternativas

Sentencia Alternativa java
  • Sintaxis:

    • <sentencia> ::= <sentenciaAlternativa> | <sentenciaAlternativaMultiple>

    • <sentenciaAlternativa> ::= if ( <expresion> ) <sentencia> [ else <sentencia> ] ;

  • <sentenciaAlternativaMultiple> ::= switch ( <expresion> ) { { case <literal> : { <sentencia> | break; } } [ default: { <sentencia> | break; } ] } ;

  • Semántica:

    • Sentencia alternativa, si se cumple la condición, ejecuta la sentencia

    • Sentencia alternativa compuesta, si se cumple la condicion, ejecuta la primera sentencia, en caso contrario la segunda sentencia

    • Sentencia alternativa múltiple, con ramas restringidas a casos concretos de valores, ejecuta desde la igualdad con la evaluación de la expresión hasta el final de la sentencia

      • break, termina la ejecución de la sentencia (p.e.: for, …​)

        • No recomendado en ninguna otra situación

package es.usantatecla.a0_itinerario.a2_estructurada.a1_alternativa;

class App {
    
    public static void main(String[] args) {
        Console console = new Console();
        int x = 0;

        if (x>=0)
            x++;
        console.writeln(x); // 1
                    
        if (x>1)
            x++;
        else
            x--;
        console.writeln(x); // 0
        
        switch(x){
            case 3:
                console.writeln("esperado"); // 
                break;
            case 2:
                console.writeln("vulgar"); // 
            case 0:
            case 1:
                console.writeln("mágico"); // mágico
                break;
            default:
                console.writeln("otro"); //    
        }
    }
}
Aplicaciones

Sentencias Iterativas

Sentencia Iterativa java
  • Sintaxis:

    • <sentencia> ::= <sentenciaIterativa>

    • <sentenciaIterativa> ::= <sentenciaWhile> | <sentenciaDoWhile> | <sentenciaFor>

    • <sentenciaWhile> ::= while ( <expresion> ) <sentencia>

    • <sentenciaDoWhile> ::= do { <sentencia> } while ( <expresion> ) ;

    • <sentenciaFor> ::= for ( [ <sentenciaLet> ] [ <expresion> ] ; [ <expresion> ] ) <sentencia>

  • Semántica:

    • Sentencia while, mientras se evalúa la expresión a cierto, ejecuta la sentencia de 0 a n veces

    • Sentencia do-while, ejecuta la sentencia mientras se evalúa la expresión a cierto de 1 a n veces

    • Sentencia for,

      • se crean los índices de las sentencia let

      • mientras se evalua a cierto la primera expresión, se ejecuta la sentencia y se evalúa la segunda expresión

package es.usantatecla.a0_itinerario.a2_estructurada.a2_iterativa;

public class App {

    public static void main(String[] args) {
        Console console = new Console();
        int x = 3;
        while (x > 0)
            x--;
        console.writeln(x); // 0

        do {
            x++;
        } while (x < 3);
        console.writeln(x); // 3

        for (int i = 0, j = 9; i < j; i++, j--)
            console.writeln(i + " - " + j); // 0 - 9 / 1 - 8 / 2 - 7 / 3 - 6 / 4 - 5
    }
}
Aplicaciones

Sentencia Secuencial

Sentencia Secuencial java
  • Sintaxis:

    • <sentencia> ::= <sentenciaSecuencial>

    • <sentenciaSecuencial> ::= { { <sentencia> }+ }

  • Semántica:

    • Su ejecución (espacio/tiempo) ejecuta secuencialmente las sentencias anidadas

package es.usantatecla.a0_itinerario.a2_estructurada.a3_secuencial.a1_sinVariables;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    {
      console.writeln("- Inicio secuencial");
      {
        console.writeln("  - Inicio secuencial interno");
        {
          console.writeln("    - Hasta el infinito");
          console.writeln("    - y más allá ... no!");
        }
        console.writeln("  - Fin secuencial interno");
      }
      console.writeln("- Fin secuencial");
    }

    console.writeln("- Inicio secuencial");
    console.writeln("  - Inicio secuencial interno");
    console.writeln("    - Hasta el infinito");
    console.writeln("    - y más allá ... no!");
    console.writeln("  - Fin secuencial interno");
    console.writeln("- Fin secuencial");
  }
}
Ámbito de bloque java
  • Define un ámbito léxico (espacio) desde su apertura ({) hasta su cierre (})

    • puede contener declaración de variables y constantes accesibles desde su declaración hasta el cierre del ámbito léxico

    • pero dos variables no pueden tener igual nombre en el mismo ámbito léxico

  • Reglas de acceso a variables y/o constantes desde las expresiones:

    • una variable o constante mencionada, se busca en su ámbito léxico hacia atras, si no se encontrara, se busca en el ámbito léxico superior hacia atrás, recursivamente hasta encontrarla …​

    • en caso contrario, se considerará como asignación o acceso desde una expresión a una variable del ámbito global creada en última instancia (sentencia var)

    • Siempre de dentro hacia afuera!, según sus ámbito léxico, desde la apertura hasta su cierre

    • Nunca desde fuera hacia dentro!!!, ocultación de información

    • cuando termina la ejecución de la sentencia, se destruyen todas las posibles variables y constantes creadas internamente

package es.usantatecla.a0_itinerario.a2_estructurada.a3_secuencial.a2_conVariables;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    int nivel0 = 100;
    console.writeln("---");
     // nivel2++;
     // console.writeln(nivel2);
     // nivel1++;
     // console.writeln(nivel1);
    nivel0++;
    console.writeln(nivel0); // 101
    
    {
      int nivel1 = 200;    
      console.writeln("---");
      // nivel2++;
      // console.writeln(nivel2);
      nivel1++;
      console.writeln(nivel1); // 201
      nivel0++;
      console.writeln(nivel0); // 102
    
      {
        int nivel2 = 300;
        console.writeln("---");
        nivel2++;
        console.writeln(nivel2); // 301
        nivel1++;
        console.writeln(nivel1); // 202
        nivel0++;
        console.writeln(nivel0); // 103
      }    
       console.writeln("---");
      // nivel2++;
      // console.writeln(nivel2);
      nivel1++;
      console.writeln(nivel1); // 203
      nivel0++;
      console.writeln(nivel0); // 104
    }
    console.writeln("---");
     // nivel2++;
     // console.writeln(nivel2);
     // nivel1++;
     // console.writeln(nivel1);
    nivel0++;
    console.writeln(nivel0); // 105
    
    {
      console.writeln("---");
     // nivel2++;
     // console.writeln(nivel2);
     // nivel1++;
     // console.writeln(nivel1);
      nivel0++;
      console.writeln(nivel0); // 106
    }    
  }
}
Ámbito de bloque java
  • Permite la ejecucuión alternativa o iterativa de varias sentencias

package es.usantatecla.a0_itinerario.a2_estructurada.a3_secuencial.a4_agrupacion;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    int x = 3;
    while (x > 0) {
      console.write(x + ", "); // 3, 2, 1,
      x--;
    }
    console.writeln(x + "."); // 0.
    
    do {
      console.write(x + ", "); // 0, 1, 2,
      x++;
    } while (x < 3);
    console.writeln(x + "."); // 3.
    
    for (int i = 0; i < x; i++){
      console.write(i + ": "); 
      console.write(x + ", "); 
    }
    console.writeln(); // 0: 3, 1: 3, 2: 3,
    
    for (int i = x; 0 < i; i--){
      console.write(i + ": "); 
      console.write(x + ", "); 
    }
    console.writeln(); // 3: 3, 2: 3, 1: 3,
  }
}
Aplicaciones

Tablas

Creación java
  • Sintaxis:

    • <expresion> ::= [ new <tipo> [ ] + ] { [ <expresion> { , <expresion> } ] } | new <tipo> [ <expresion> ] + [ ] *

    • <sentenciaFor> ::= for ( <tipo> <identificador> : <expresión> ) <sentencia>

  • Semántica:

    • El operador new es unario prefijo cuyos operandos son tipo de tablas y devuelve la dirección de memoria donde se ha reservado el espacio para dicha tabla

      • su nivel de precedencia es igual al de los operadores unarios.

      • donde el vector se crea con n elementos inicializados con 0, false o '\0' los tipos numéricos, lógicos o caracteres respectivamente o con los valores de la evaluación de las expresiones correspondientes

    • Tipo de dato estructurado/compuesto que permite almacenar un conjunto de datos bajo un mismo identificador, tabla, vector, matriz, retícula, rejilla, …​ array

      • Cada uno de los elementos que componen un vector pueden ser de cualquier tipo:

        • tipo primitivo, number, string, boolean, undefined;

        • tipo estructurado/compuesto como los propios arrays pudiendo construir arrays de arrays de tipos primitivos, tablas bidimensionales, …​ arrays de arrays de …​ de tipos primitivos, tablas n-dimensionales

      • Recomendado que sea una colección de elementos homogéneos, todos ellos del mismo tipo y de la misma naturaleza: no combinar 5 contadores y un acumulador

package es.usantatecla.a0_itinerario.a2_estructurada.a4_tablas.a1_creacion;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        for (int value : new int[] {}) {
            console.write(value); //
        }
        console.writeln();
        for (int value : new int[] { 1, 2, 3, 4, 5 }) {
            console.write(value + ", "); // 1, 2, 3, 4, 5,
        }
        console.writeln();
        for (String value : new String[] { "Java", "Javascript", "Scala" }) {
            console.write(value + ", "); // Javascript, Java, Scala
        }
        console.writeln();
        for (boolean value : new boolean[] { false, true }) {
            console.write(value + ", "); // false, true
        }
        console.writeln();
        boolean b = false;
        for (boolean x : new boolean[] { true, b, 5 + 6 > 5 - 6 }) {
            console.write(x + ", "); // true, false, true,
        }
        console.writeln();
        for (char[] vowels : new char[][] {
                { 'a', 'e', 'i', 'o', 'u' },
                { 'A', 'E', 'I', 'O', 'U' } }) {
            for (char vowel : vowels) {
                console.write(vowel + ", "); // a, e, i, o, u, A, E, I, O, U
            }
        }
        console.writeln();
        for (char[] row : new char[][] {
                { 'x', ' ', 'o' },
                { 'x', 'o', 'o' },
                { ' ', ' ', 'x' } }) {
            for (char token : row) {
                console.write(token + ", "); // x, ,o, x, o, o, , ,x
            }
        }
        console.writeln();
        for (int[][] tableData : new int[][][] {
                {
                        { 0, 0, 0 },
                        { 0, 0 },
                        { 0 } },
                {
                        {},
                        { 1, 2, 3, 4 } } }) {
            for (int[] row : tableData) {
                for (int value : row) {
                    console.write(value + ", "); // 0, 0, 0, 0, 0, 0, 1, 2, 3, 4
                }
            }
        }
        console.writeln();
        for (int value : new int[3 * 2]) {
            console.write(value + ", "); // 0, 0, 0, 0, 0, 0,
        }
        console.writeln();
        int length = 3;
        for (boolean[] row : new boolean[length - 1][2]) {
            for (boolean value : row) {
                console.write(value + ", "); // false, false, false, false,
            }
        }
        console.writeln();
        int[][] notIntsOnlyRows = new int[10][];
    }
}
Acceso a elementos java
  • Sintaxis:

    • <expresión> ::= <expresión> [ <expresión> ]

    • <expresión> ::= <expresión> .length

  • Semántica:

    • mediante la indexación del array dado por la primera expresión con la posición deseada a través de la segunda expresión entera comenzando por 0 para el primer elemento

    • mediante la propiedad length se accede a la cantidad del elementos del array dado por la expresión, uno más del índice del último elemento porque empieza por 0

    • sentencias for especiales para arrays

      • donde la variable declarada tomará cada uno de los valores del array en el orden natural

package es.usantatecla.a0_itinerario.a2_estructurada.a4_tablas.a2_acceso;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        console.writeln(new int[] { 1, 2, 3, 4, 5 }[0]); // 1
        console.writeln(new int[] { 1, 2, 3, 4, 5 }[4]); // 5
        //console.writeln(new int[] { 1, 2, 3, 4, 5 }[5]); // ERROR
        console.writeln(new String[][] { 
            { "a", "b", "c" }, 
            { "x", "y", "z" } }[0][0]); // a
        for(String value : new String[][] { 
            { "a", "b", "c" }, 
            { "x", "y", "z" } }[1]){
            console.write(value + ", "); // x, y, z,
        }
        console.writeln();
        console.writeln(new int[] { 0, 1, 2 }.length); // 3
        console.writeln(new String[][] { 
            { "a" }, 
            { "x", "y", "z" } }[0].length); // 1
        console.writeln(new String[][] { 
            { "a" }, 
            { "x", "y", "z" } }[1].length); // 3
        console.writeln(new String[][] { 
            { "a" }, 
            { "x", "y", "z" } }.length); // 2
    }
}
Referencias java
  • Sintaxis:

    • <sentencia> ::= ( byte | short | int | long | float | double | char | String | boolean ) ( [ ] ) \+ <identificador> [ = <expresion> * [red]]*

  • Semántica:

    • son variables/constantes declaradas no almacenan el valor compuesto del array, como ocurre con los tipos primitivos, sino que almancenan la dirección/"referencia" a la memoria donde se almacenan los valores del tipo compuesto

package es.usantatecla.a0_itinerario.a2_estructurada.a4_tablas.a3_referencia;

class App {

    public static void main(String[] args) {
        Console console = new Console();
        int[] array = new int[] { 1, 2, 3, 4, 5 };
        console.writeln(array[0]); // 1
        console.writeln(array[4]); // 5
        // console.writeln(array[5]); // ERROR!!!
        console.writeln(array.length); // 5

        int primitive1 = 1;
        int primitive2 = primitive1;
        console.writeln(primitive1); // 1
        console.writeln(primitive2); // 1
        primitive2 = 2;
        console.writeln(primitive1); // 1
        console.writeln(primitive2); // 2

        int[] array1 = new int[] { 1, 2, 3 };
        for(int value : array1) {
            console.write(value + ", "); // 1, 2, 3
        }
        console.writeln();
        int[] array2 = array1;
        for(int value : array2) {
            console.write(value + ", "); // 1, 2, 3
        }
        console.writeln();
        array1[1] = 666;
        for(int value : array1) {
            console.write(value + ", "); // 1, 666, 3
        }
        console.writeln();
        for(int value : array2) {
            console.write(value + ", "); // 1, 666, 3
        }
        console.writeln();
        console.writeln(array1 == array2); // true

        array1 = new int[] { 1, 666, 3 };
        for(int value : array1) {
            console.write(value + ", "); // 1, 666, 3
        }
        console.writeln();
        for(int value : array2) {
            console.write(value + ", "); // 1, 666, 3
        }
        console.writeln();
        console.writeln(array1 == array2); // false

        array2[1] = 0;
        for(int value : array1) {
            console.write(value + ", "); // 1, 666, 3
        }
        console.writeln();
        for(int value : array2) {
            console.write(value + ", "); // 1, 0, 3
        }
        console.writeln();
        console.writeln(array1 == array2); // false

        for (int value : array1) {
            console.write(value + ", "); // 1, 666, 3,
        }
        console.writeln();
        for (int i = 0; i < array1.length; i++) {
            console.writeln(i + ": " + array1[i] + ", "); // 0: 1, 1: 666, 2: 3,
        }
        console.writeln();
    }
}
Modificación de elementos java
  • Sintaxis:

    • <sentAsignacion> ::= <expresión> [ <expresión> ] = <expresión> ;

  • Semántica:

    • mediante la asignación del valor de la evaluación de una expresión (3), en la posición indexada mediante el valor entero de la expresión (2) del array dado por la primera expresión (1)

package es.usantatecla.a0_itinerario.a2_estructurada.a4_tablas.a4_modificacion;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    int[][] bidimensional = new int[][] {
        { 1, 2, 3 },
        { 0 },
        { 9, 8, 7 }
    };
    int[] temp = bidimensional[0];
    bidimensional[0] = bidimensional[1];
    bidimensional[1] = bidimensional[2];
    bidimensional[2] = temp;
    for(int[] unidimensional : bidimensional){
      for(int atom : unidimensional){
        console.writeln(atom);
      }
    }
  }
}
Valor null java
  • Sintaxis:

    • <literal> ::= null

  • Semántica:

    • la dirección null es el valor de aquella dirección donde no hay valores

package es.usantatecla.a0_itinerario.a2_estructurada.a4_tablas.a5_null;

class App {

  public static void main(String[] args) {
    Console console = new Console();
    int[][] array = new int[][] { { 1, 666, 3 }, null, { 0 } };
    for (int[] row : array) {
      if (row != null) {
        for (int value : row) {
          console.writeln(value + ", "); // 1, 666, 3, 0
        }
      }
    }
    array[2] = null;
    array[1] = array[0];
    for (int[] row : array) {
      if (row != null) {
        for (int value : row) {
          console.writeln(value + ", "); // 1, 666, 3, 1, 666, 3,  
        }
      }
    }
  }
}
Aplicaciones

Programación Basada a Objetos

  • Una clase es una colección heterogénea de

    • atributos, variables o constantes o colecciones de éstos u otros objetos cuyos valores determinan las características del concepto, módulo, unidad, …​

    • y métodos, algoritmos disponibles para manipular (añadir, eliminar, modificar, consultar) las características del concepto, módulo, unidad, …​

  • Debe respetar los principios de diseño de alta cohesión, bajo acoplamiento y pequeño tamaño del diseño modular

  • la clase Intervalo implanta el concepto de un segmento limitado por un mínimo y un máximo:

    • intervalo de horas laborales [8,15]

    • intervalo de la capacidad de memoria de los pc’s de un laboratorio [1.2,4]

    • intervalo de la tensión arterial aconsejable para una persona [8.4,14.3]

    • …​

  • contempla operaciones como:

    • desplazar

    • longitud_

    • …​

Vista Pública de las Clases

Nombre de la Clase

Sintaxis Ejemplo
class  <NombreClase> {
}
class Interval {
}
class Coordinate {
}

Cabecera de Métodos de la Clase

Sintaxis

Ejemplo

public <tipo1> <nombreMetodo> ( {<tipo2> <parametro>, ...}* )
  • el tipo1 indica el tipo del valor devuelto, que puede ser:_

    • void, nada, dado que el efecto será un cambio de estado en el objeto y/o sistema

    • <primitivo/Clase>, un valor de tipo primitivo o una referencia a un objeto de una clase

    • <primitivo/Clase>[], una referencia a un vector de valores de tipos primitivos o de referencias a objetos

    • <primitivo/Clase>[][], una referencia a una matriz de valores de tipos primitivos o de referencias a objetos

    • …​

  • el nombre del método debe comenzar con minúscula_

  • el tipo2 puede ser igual que tipo1 excepto_ void

    • todos los parámetros son pasados por valor

class Interval {
  public void shift(double shiftment) {...}
  public void adjust(Interval interval) {...}
  public double length() {...}
  public boolean includes(Interval interval) {...}
  public boolean equals(Interval interval) {...}
  public Interval symetric() {...}
  public Interval shifted(double shifment) {...}
  public Interval intersección(Interval interval) {...}
  public double[] values(int times) {...}
  public Interval[] split(int times) {...}
  ...
}

Sobrecarga de Métodos de la Clase

Descripción Ejemplo
  • Varios métodos pueden tener el mismo nombre con las siguientes restricciones:

    • si están en la misma clase, deben diferenciarse en el número o tipo de parámetros comparados dos a dos;

    • si están en distintas clases, no existe restricción;

class Interval {
  public Interval(double min, double max) {...}
  public Interval(double max) {...}
  public Interval() {...}
  public Interval(Interval interval) {...}
  public Interval(String string) {...}
  public boolean includes (double point) {...}
  public boolean includes (Interval interval) {...}
  public boolean isValid() {...}
  ...
}

class Coordinate {
  public boolean isValid ()
  ...
}

Constructores de la Clase

Descripción Ejemplo
  • Son métodos que reúnen las tareas de inicialización, no construyen, y se lanzan implícimatemente en la construcción de objetos. Cumplen:

    • no devuelven nada, ni void;

    • deben coincidir su nombre con el de la clase;

    • no se pueden lanzar mensajes que se correspondan con los constructores de la clase._

class Interval {
  public Interval(double min, double max) {...}
  public Interval(double max) {...}
  public Interval() {...}
  public Interval(Interval interval) {...}
  public Interval(String string) {...}
  ...
}

Destructores de la Clase

Descripción Ejemplo

Son métodos que reúnen las tareas de liberación de recursos (no destruyen) y se lanzan automáticamente en la destrucción de objetos. Además:

  • su cabecera debe ser:

public void finalize()
  • no se pueden lanzar mensajes que se correspondan con los destructores de la clase.

Vista Pública de los Objetos

Creación de objetos

Sintaxis f

Ejemplo

new es un operador unario prefijo cuyo operando es una clase de objetos y devuelve la dirección de memoria donde se ha reservado el espacio para dicho objeto;

height32
  • donde la lista de expresiones debe coincidir con la lista de parámetros de alguno de los constructores de la clase; en caso de no existir, la lista debe ser vacía.

new Intervalo()
new Intervalo(100)
new Intervalo(11.5, 55.1)
new Intervalo(new Intervalo(-1, 1))

Referencia a un objeto

Sintaxis Ejemplo

Es una variable puntero que alberga la dirección de un objeto de una clase.

height32
  • final obliga a la inicialización y fija su valor para la referencia

height32
Operadores Ejemplo:
  • <referenciaO> = <direcciónO>: asigna la dirección a la referencia siendo del mismo tipo;

  • <direcciónO-I> == <direcciónO-D>: determina si dos direcciones a objetos de la misma clase son iguales;

  • <direcciónO-I> != <direcciónO-D>: determina si dos direcciones a objetos de la misma clase son distintas;

final Intervalo HORARIO = new Intervalo(7, 15);
Intervalo edades = new Intervalo(100);
Intervalo años;
años = edades;
boolean mismo = edades == años;

Paso de mensajes

Sintaxis Ejemplo
<expressioin>.<methodName>([<expression>{, <expression>})]
  • donde el método (sin contemplar constructores ni destructores) debe estar presente en la interfaz de la clase del objeto y la lista de expresiones debe coincidir en número y tipos a la lista de parámetros del método;

intervalo.longitud()
new Intervalo(-100, 100).longitud()
edades.partido(5)
años.incluye(88)
edades.interseccion(años)
...

Creación de vectores de objetos

Sintaxis g Ejemplo

new es operador unario prefijo cuyo operando es un vector de referencias a objetos de una clase y devuelve la dirección de memoria donde se ha reservado el espacio para dicho vector;

height32
  • donde la expresión debe ser de tipo entero y determina la longitud de referencias del vector inicializadas a null;

new Intervalo[100]
Sintaxis h Ejemplo
new <Clase>[] {<expresion>,..., <expresion>}
  • donde cada expresión debe ser una dirección a un objeto de la clase que inicializan las referencias del vector creado de longitud igual al número de expresiones;

   Intervalo intervalo = new Intervalo();
new Intervalo[] {new Intervalo(), null, intervalo}
height32

Referencia a un vector de referencias a objetos

Definición Sintaxis Ejemplo

Es una variable puntero que alberga la dirección de un vector de referencias a objetos de una clase.

heigt32
  • final obliga a la inicialización y fija su valor para la referencia

Intervalo[] intervalos;
height32
Intervalo[] intervalos = new Intervalo[10];
intervalos[0] = new Intervalo ();
intervalos[1] = intervalos[0].desplazados(1);
intervalos[intervalos.length-1] = new Intervalo(2,2);
Intervalo intervalo = intervalos[1];
intervalos = null;(1)
...
1 Se libera automáticamente toda la memoria de las referencias del vector y de cada objeto excepto del segundo intervalo porque nadie está apuntando a dichos elementos;

Vista Privada de las Clases

Definición de Atributos Definición de Constructores Definición de Métodos Referencia this Métodos privados
  • datos constantes y/o variables de tipos primitivos y/o referencias a objetos y/o tablas

  • inicialización de los atributos de la clase

  • operaciones con sentencias secuenciales, alternativos, iterativas, expresiones (asignación) y/o de retorno

  • para la resolución de colisión de identificadores y reutilización de métodos dentro de la clase

  • para la reutilización de métodos dentro de la clase

Aserciones Objetos valor
  • verificación del correcto estado del entorno del mensaje, atributos, parámetros, entorno, …​ para la seguridad al procesar los datos

  • clases cuyos objetos no cambian de estado (conjunto de estados de sus atributos) tras su creación

Definición de atributos

  • Se declaran variables y/o constantes de tipos primitivos, referencias a objetos o vectores de éstos

  • anteponiendo la palabra private

    • En cualquer punto de la implementación de la clase pero lo lógico es al principio de la declaración de la clase

class <class> {
   private <declaration>
   private <declaration>
   ...
}
class Interval {
   private double min;
   private double max;
}

Definición de constructores

  • Reservado para las tareas de inicialización de los atributos del objeto, evitando la creación de objetos incosistentes

    • A falta de inicialización explícita, no recomendado, se inicializan a valores por defecto, dependiendo de su tipo (0 para tipos numéricos, false para el tipo boolean, caracter nulo para tipo char y null para referencias);

class Interval

  private double min;
  private double max;

  public Interval(){
    min = 0;
    max = 0;
  }

  public Interval(double maximum){
    min = 0;
    max = maximum;
  }

  public Interval(double minimum, double maximum){
    min = minimum;
    max = maximum;
  }
  ...

Definición de metodos

  • En cualquier punto de la implementación de la clase, se define el cuerpo de las cabeceras de los métodos acompañándolos de una sentencia secuencial que contiene las declaraciones locales y sentencias que se consideren oportunas

    • dentro del cuerpo del método se tiene acceso a los atributos, los parámetros del método y a las declaraciones locales desde las expresiones de la anidación jerárquica de sentencias

    • la notación punto para el paso de mensajes sirve también para acceder a los atributos de un objeto de la misma clase

clase <class> {
  public <methodHeader> <sequentialSentence>
  public <methodHeader> <sequentialSentence>
  ...
}
class Interval {
  private double min;
  private double max;

  public void shift (double amount) {
    min += amount;
    max += amount;
  }

  public Interval(Interval interval){
    min = interval.min;
    max = interval.max;
  }

  public boolean equals(Intervalo interval) {
    return min == interval.min && max == interval.max;
  }
  ...
  • si el tipo devuelto no es_ void, se determinará el valor devuelto por el método con la siguiente sentencia:

  return <expression>;
public double length() {
  return max - min;
}

public boolean includes(double point) {
  return min <= point && point <= max;
}

public boolean valid() {
  return min <= max;
}

Referencia this

  • this es una referencia constante que guarda la dirección del objeto que recibe el mensaje correspondiente al método que se está definiendo, implícitamente existe en todas las clases:

  private final <class> this;
  • Sirve para resolución de ambigüedades en la colisión de parámetros o declaraciones locales con el mismo nombre que los atributos;

    • Evita la multiplicidad de identificadores innecesarios

public Interval(double min, double max) {
  this.min = min;
  this.max = max;
}
  • Sirve para la reutilización de contructores en la definición de otros constructores, siendo la primera sentencia del constructor, mediante la sintaxis:

  this([ <expression> {, <expression> }]);
  public Interval() {
    this(0, 0);
}

  public Interval(double max) {
    this(0, max);
  }

  public Interval(Interval interval) {
    this(interval.min, interval.max);
  }
  • Sirve para la reutilización de métodos en la codificación de otros métodos;

public boolean includes(Interval interval) {
  return this.includes(interval.min) &&
    this.includes(interval.max);
}

public void escale(double escale) {
  final double newHalfLength = this.length()/2 * escale;
  final double middlePoint = this.middlePoint();
  this.min = middlePoint - newHalfLength;
  tnis.max = middlePoint + newHalfLength;
}

Métodos privados

  • Sirve para la reutilización de métodos en la codificación de otros métodos

    • dado que puede ser conveniente disponer de métodos, que no han sido solicitados, para implementar otros métodos, cabe la posibilidad de definir métodos de ámbito privado que sólo se pueden usar en la implementación de la clase:

class <class> {
   private <methodHeader> <sequentialSentence>
   private <methodHeader> <sequentialSentence>
   ...
}
public Interval shifted(double amount) {
   Interval interval = this.clone();
   interval.shift(amount);
   return interval;
}

private Interval clone() {
  return new Interval(this);
}
Aplicaciones

Aserciones

  • Error es una acción que produce un resultado incorrecto

  • Defecto es la imperfección de un componente causado por un error

  • Fallo es la manifestación visible de un defecto

  • Ej. un conductor analiza mal el contexto de la circulación

  • Ej. un programador escribe mal una sentencia, incumpliendo reglas léxico/ sintáctico/ semánticas

  • Ej. un programador diseña mal un algoritmo, produciendo un bucle infinito

  • Ej. un conductor establece una velocidad, giro, …​ inadecuados

  • Ej. un programa produce una incompatibilidad de tipos entre un operador y un operando

  • Ej. un programa con una condición en una sentencia iterativa infinita

  • Ej. se produce un accidente

  • Ej. el programa no compila

  • Ej. el programa no responde

Tipos de Errores
  • Errores en Tiempo de Compilación producidos por el incumplimiento de las

    • reglas léxicas,

    • reglas sintácticas y/o

    • reglas semánticas del lenguaje fuerte o débilmente tipado;

  • Errores en Tiempo de Ejecución

  • Errores Lógicos producidos por la lógica de un programa que no contempla todos los posibles situaciónes del sistema de información

    • Se gestionan con sentencias assert para las pre-condiciones

    • Se gestionan con pruebas del software para las post-condiciones

  • Errores Excepcionales producidos por recursos (bibliotecas / frameworks para gestión de ficheros, comunicaciones, …​, arquitectura) fuera del ámbito del software que los maneja.

    • Se gestionan con objetos de la clase Exception y la sentencia try/catch/finally

Contexto Aplicación Biblioteca
  • ciertos errores lógicos (ej.: un valor negativo para calcular un factorial, una referencia sin la dirección del objeto, …​) pueden ser un error lógico o excepcional dependiendo del software en el que se está desarrollando:

  • debe responsabilizarse de la detección y subsanación de los errores lógicos dentro de su ámbito durante el desarrollo.

    • los errores en la entrada de datos del usuario no son errores del desarrollo y se solventan mediante la validación de la entrada de datos, sentencia iterativa hasta alcanzar la condición deseada

  • NO puede responsabilizarse del uso indebido de los servicios prestados a las aplicaciones y NUNCA debe responsabilizarse de la subsanación de dichos errores.

    • En estos casos, estos errores lógicos se considerarán excepcionales porque la causa del error está fuera de los límites del software de la biblioteca.

Ej. la función factorial contemplará:

  • pre-condiciones para verificar si la entrada es correcta (el argumento no es negativo) mediante

  • la sentencia assert en el código de producción

  • la elevación de una excepción en el código de producción

  • post-condiciones para verificar si la salida es correcta (n! = 1 si n = 0 si no n * (n-1)!) mediante la librería aseertThat en el código de pruebas

class Interval {
  ...
  public Interval[] split(int times) {
    Interval[] intervals = new Interval[times];
    final double length = this.length() / times;
    final double min = this.min;
    final double max = min + length;
    for (int i = 0; i < times; i++) {
      intervals[i] = new Interval(min, max);
      min = max;
      max += length;
    }
    return intervals;
  }
  ...
}

class App {

  public static void main(String[] args){
    Console console = new Console();
    Interval interval = new Interval();
    interval.read();
    int times = console.readInt("¿Partir en cuántas veces? ");
    Interval[] intervals = interval.split(times);
  }
}
  • cuando se solicita el número de veces, si el usuario introduce un valor negativo, se produce un error de ejecución, se muestra por pantalla un informe del error producido (reserva de un vector cuyo tamaño es negativo), y finaliza la ejecución del programa

Introduce el minimo: 1
Introduce el maximo: 5
Veces: -1
Exception in thread "main" java.lang.NegativeArraySizeException
        at Intervalo.valores (Intervalo.java:141)
        at Aplicacion.main (Aplicacion.java:7)
Programación defensiva
  • si se trata de una aplicación, la solución NO es que el método compruebe la corrección de su argumento y que, en el caso de que no sea correcto, gestione el error acoplándose con un mensaje a la consola, …​:

class Interval {
  ...
  public Interval[] split(int times) {
    if (times < 0) {
      new Console().writeln("El numero de veces debe ser positivo");
      return null;
    }
    Interval[] intervals = new Interval[times];
    final double length = this.length() / times;
    final double min = this.min;
    final double max = min + length;
    for (int i = 0; i < times; i++) {
      intervals[i] = new Interval(min, max);
      min = max;
      max += length;
    }
    return intervals;
  }
}
  • si se trata de una aplicación, la solución NO es que el método compruebe la corrección de su argumento y que, en el caso de que no sea correcto, devuelva una valor que indique que hay un error:

class Interval {
  ...
  public Interval[] split(int times) {
    if (times < 0) {
      return null;
    }
    Interval[] intervals = new Interval[times];
    final double length = this.length() / times;
    final double min = this.min;
    final double max = min + length;
    for (int i = 0; i < times; i++) {
      intervals[i] = new Interval(min, max);
      min = max;
      max += length;
    }
    return intervals;
  }
}
Falta de cohesión Validación de datos
class App {

  public static void main(String[] args){
    Console console = new Console();
    Interval interval = new Interval();
    interval.read();
    Interval[] intervals;
    do {
      int times = console.readInt("¿Partir en cuántas veces? ");
      intervalos = intervalo.troceado(veces);
    } while (intervalos != null);
  }
}
  • si se trata de una aplicación, la solución es que, al leer el argumento, se valide su corrección y que, en el caso de que no sea correcto, no se invoque al método y se comunique y requiera de nuevo al usuario:

class App {

  public static void main(String[] args){
    Console console = new Console();
    Interval interval = new Interval();
    int times;
    do {
      times = console.readInt("¿Partir en cuántas veces? ");
      if (times <= 0) {
         console.writeln("El numero de veces debe ser positivo");
      }
    } while (times <= 0);
    Interval[] intervals = interval.split(times);
  }
}
Sentencia assert Ejemplo
  • Sintaxis

  assert <expresión1> [ : <expresión2> ] ;
  • Cada aserción contiene una expresión lógica (<expresión1>) que se supone cierta cuando se ejecute la sentencia

    • en caso contrario, el sistema finaliza la ejecución del programa y avisa del defecto detectado

    • opcionalmente, se puede acompañar de una cadena de caracteres (<expresión2>) para detallar el error detectado

  • La experiencia ha demostrado que escribir aserciones es una de las formas más rápidas y efectivas para detectar y corregir errores lógicos en desarrollo, Diseño por Contrato

    • si se desea comprobar en el método la corrección de su argumento, debe incluirse una aserción como pre-condiciones

    • las aserciones permiten eliminar estas comprobaciones automáticamente en la ejecución del código de producción para evitar la finalización abrupta del programa en fase de explotación

class Interval {
  ...
  public Interval[] split(int times) {
    assert times > 0 : "El numero de veces no es positivo";

    Interval[] intervals = new Interval[times];
    final double length = this.length() / times;
    final double min = this.min;
    final double max = min + length;
    for (int i = 0; i < times; i++) {
      intervals[i] = new Interval(min, max);
      min = max;
      max += length;
    }
    return intervals;
  }
}
  • si se está desarrollando una biblioteca, entonces sí que deberemos responsabilizarnos de comprobar los argumentos que se reciben en los métodos, porque están fuera del ámbito de la biblioteca, junto con la consiguiente gestión de excepciones para comunicar de la situación al error:

class Interval {
  ...
  public Interval[] split(int times) throws Exception {
    if (times < 0) {
      throw new Exception("El numero de veces no es positivo")
    }

    Interval[] intervals = new Interval[times];
    final double length = this.length() / times;
    final double min = this.min;
    final double max = min + length;
    for (int i = 0; i < times; i++) {
      intervals[i] = new Interval(min, max);
      min = max;
      max += length;
    }
    return intervals;
  }
}
class App {

  public static void main(String[] args){
    Console console = new Console();
    Interval interval = new Interval();
    int times;
    ...
    try {
      Interval[] intervals = interval.split(times);
      ...
    } catch (Exception ex){
      // gestión de error
    }
  }
}
Aplicaciones

Objetos Valor

  • En el caso de que los atributos sean constantes, puede postergarse la inicialización obligatoria al cuerpo de todos los constructores.

    • Una vez inicializadas, ya no es posible la asignación de nuevos valores.

class Person  {
  public final short ADULT = 18;
  private short age;
  private final int DNI;

  public Person(int dni) {
    age = 0;
    DNI = dni;
  }
  ...
}
Aplicaciones

Vista Privada de los Objetos

Desencadenamiento de instanciaciones Desencadenamiento de mensajes
  • se crea un objeto (instancia):

    • por lo que, se crean los atributos definidos en la clase;

    • por lo que, se ejecuta la inicialización de los atributos con posibles creaciones de nuevos objetos;

    • por lo que, se ejecuta el constructor en la creación del objeto con posibles creaciones de nuevos objetos;

    • Donde, recursivamente, pueden crear nuevos objetos de otras clases hasta llegar, de esta manera, a la creación de objetos que se basan directamente en tipos primitivos.

  • se lanza un mensaje a un objeto:

    • por lo que se crean las declaraciones locales con su inicialización y se ejecuta el cuerpo del método correspondiente

    • por lo que se pueden lanzar nuevos mensajes a objetos que sean atributos de su clase, a objetos que sean argumentos del mensaje o a objetos que se crean en su ejecución

    • Donde, recursivamente, pueden lanzar nuevos mensajes en la definición de sus respectivos métodos hasta llegar, de esta manera, a la definición de métodos que se basan directamente en tipos primitivos.

class Person {
  ...
  private MedicalRecord medicalRecord;
  private AcademicRecord academicRecord;
  ...

  public Person(...) {
    ...
    this.medicalRecord = new MedicalRecord();
    this.academicRecord = new AcademicRecord();
    ...
  }
}

class MedicalRecord {
  ...
}

class AcademicRecord {
  ...
}
class Person {
  ...

  public boolean isAdult() {
    return this.age > Person.ADULT;
  }

  public void writeln() {
    ...
    new Console.writeln("Age: " + this.age + (this.isAdult() ? " (adult)" : ""));
    this.medicalRecord.writeln();
    this.academicRecord.writeln();
  }

}
  • el desencadenamiento de instanciaciones puede provocar un desencadenamiento de mensajes a través de la ejecución de los constructores que pueden lanzar mensajes;

public Intervalo(Intervalo intervalo) {
  this(intervalo.minimo, intervalo.maximo);
}

private Intervalo copia() {
  return new Intervalo(this);
}
  • el desencadenamiento de mensajes puede provocar un desencadenamiento de instanciaciones a través de la creación de objetos en la definición de los métodos.

Aplicaciones

Miembros de Clase

Miembros de instancia Miembros de clase o estáticos
  • Los miembros de instancia asumen los aspectos, datos y operaciones, particulares/locales de/a cada objeto de la clase

  • Los miembros de clase o estáticos asumen los aspectos, datos y operaciones, compartidos/globales por/a la comunidad de objetos de la clase

  • atributos de instancia presentes en cada uno de los objetos de la clase;

    • Ej. día, mes y año de una fecha concreta

    • si no hay objetos, no hay atributos de instancia;

  • atributos de clase compartidos por la globalidad de objetos de la clase;

    • Ej. los nombres y duración de los meses de cualquier fecha, excepto en Febrero de años bisiestos, …​

    • si no hay objetos, si hay atributos de clase;

  • métodos de instancia cuyos mensajes se lanzan sobre un objeto particular de la clase;

    • Ej. si es primavera, si una fecha concreta se encuentra en una año bisiesto, …​

    • si no hay objetos, no hay mensajes;

  • métodos de clase cuyos mensajes NO se lanzan sobre un objetos particular;

    • Ej. si un año (de cualquier fecha, no de una fecha particular) es bisiesto

    • si no hay objetos, si se llama a métodos de clase, no mensaje!!!;

Atributos y Métodos Estáticos

Atributos estáticos Métodos estáticos
  • caracterizados por la palabra reservada static tras su visibilidad;

  • su reserva de memoria e inicialización obligatoria se realiza al principio de la ejecución del programa,

    • en orden dentro de las declaraciones de la clase pero

    • en desorden entre las distintas clases

  • accesibles desde cualquier método, de instancia o estático, de la clase;

  • la notación sintáctica para el acceso desde las expresiones:

    <Clase>.<atributosEstático>
  • se permite el acceso a los atributos estáticos;

  • no se permite el acceso a this ni a los atributos de instancia;

  • la notación sintáctica para la invocación/llamada/ejecución del método estático como sentencia de los métodos:

  <Clase>.<metodoEstatico>([<argumento> { <argumento>, }])
class Fecha {
 private int dia;
 private int mes;
 private int año;
private static final int[] DIAS_MESES =
  {31,28,31,30,31,30, 31,31,30,31,30,31};

public boolean posterior(Fecha fecha) {
  boolean resultado;
  if (this.año == fecha.año)
  if (this.mes == fecha.mes)
    resultado = this.dia > fecha.dia;
  else
    resultado = this.mes > fecha.mes;
  else
    resultado = this.año > fecha.año;
  return resultado;
}

public static boolean bisiesto(int año) {
  return año%4 == 0;
}
public boolean enBisiesto() {
  return Fecha.bisiesto(año);
}

public int diasTranscurridosAño() {
  int dias = dia - 1;
  for (int i = 1; i < mes; i++)
    dias += Fecha.DIAS_MESES[i - 1];
  if (this.enBisiesto() &&
    this.posterior(new Fecha(29, 2, año)))
dias++;
  return dias;
}

public static int diasAño(int año) {
  int dias = 0;
  for (int i = 0; i < Fecha.DIAS_MESES.length; i++)
      dias += Fecha.DIAS_MESES[i];
  if (Fecha.bisiesto(año))
     dias++;
  return dias;
  }

Código estático

Sintaxis Ejemplos
  • sirve para la inicialización de los atributos estáticos cuando la inicialización posible no alcanza sus objetivos;

  • se ejecutan en cualquier orden en el comienzo de la ejecución del programa;

<atributoEstático>
static {
  <sentencia/declaración>
  
  <sentencia/declaración>
}
private static int[] coeficientes = null;
static {
  // lectura del fichero “coeficientes.sys”
}

Clases de Utilidad

En librerías y proyectos Clase System
  • Son clases que reúnen un conjunto cohesivo de métodos estáticos, …​ cajón de-sastre

  • Suelen no ser instanciables porque no responden al concepto habitual de clases de objetos

    • se consigue a través constructores privados que eviten la creación de objetos de esa clase de utilidad

class System {
  public static long currentTimeMillis() { ...}
  public static long nanoTime() { ...}
  public static void exit(int) { ...}
  public static void gc() { ...}
}
Clase Math
public static final double E;
public static final double PI;
public static double sin(double)
public static double cos(double)
public static double tan(double)
public static double asin(double)
public static double acos(double)
public static double atan(double)
public static double toRadians(double)
public static double toDegrees(double)
public static double exp(double)
public static double log(double)
public static double log10(double)
public static double sqrt(double)
public static double cbrt(double)
public static double IEEEremainder(double, double)
public static double ceil(double)
public static double floor(double)
public static double rint(double)
public static double atan2(double,double)
public static double pow(double,double)
public static int round(float)
public static long round(double)
public static double random()
public static int abs(int)
public static long abs(long)
public static float abs(float)
public static double abs(double)
public static int max(int, int)
public static long max(long, long)
...
public static float max(float, float)
public static double max(double,double)
public static int min(int, int)
public static long min(long, long)
public static float min(float, float)
public static double min(double,double)
public static double ulp(double)
public static float ulp(float)
public static double signum(double)
public static float signum(float)
public static double sinh(double)
public static double cosh(double)
public static double tanh(double)
public static double hypot(double,double)
public static double expm1(double)
public static double log1p(double)
public static double copySign(double,double)
public static float copySign(float, float)
public static int getExponent(float)
public static int getExponent(double)
public static double nextAfter(double,double)
public static float nextAfter(float,double)
public static double nextUp(double)
public static float nextUp(float)
public static double scalb(double, int)
public static float scalb(float, int)
...

Cadenas de Caracteres

Definición Constantes, inmutables Variables, mutables
  • Son secuencias de caracteres de cualquier longitud, incluso secuencia vacía

  • cuyos caracteres no varían tras la creación

    • Implementadas bajo la clase String sin contemplar métodos que modifiquen el estado del objeto.

    • Ej. El nombre de una persona, de un mes, de una universidad, de un proyecto, …​

  • cuyos caracteres sí varían tras la creación

    • Implementadas bajo las clases StringBuffer (con sincronización en concurrencia) y StringBuilder (sin) con métodos que contemplan la modificación del objeto

    • Ej. Membrete de una carta, párrafo de aviso, clausula de contrato, …​

Clase String

Clase String
public String()
public String(String)
public String(char[])
public String(char[], int, int)
public String(int[], int, int)
public String(byte[], int, int, int)
public String(byte[], int)
public String(byte[], int, int)
public String(byte[])
public String(StringBuffer)
public String(StringBuilder)
public int length()
public boolean isEmpty()
public char charAt(int)
public byte[] getBytes()
public char[] toCharArray()
public String toString()
public void getChars(int, int, char[], int)
public void getBytes(int, int, byte[], int)

public CharSequence subSequence(int,int)
public String substring(int)
public String substring(int, int)

public int hashCode()
public int indexOf(String)
public int indexOf(String, int)
public int indexOf(int)
public int indexOf(int, int)
public int lastIndexOf(String)
public int lastIndexOf(String, int)
public int lastIndexOf(int)
public int lastIndexOf(int, int)
public int codePointAt(int)
public int codePointBefore(int)
public int codePointCount(int, int)
public int offsetByCodePoints(int, int)

public boolean equals(Object)
public boolean equalsIgnoreCase(String)
public boolean contentEquals(StringBuffer)
public boolean matches(String)
public boolean regionMatches(int,String, int, int)
public boolean regionMatches(boolean,int, String,int, int)
public boolean startsWith(String, int)
public boolean startsWith(String)
public boolean endsWith(String)
public int compareTo(String)
public int compareToIgnoreCase(String)
public String[] split(String)
public String[] split(String, int)

public String concat(String)
public String replace(char, char)
public String replaceFirst(String, String)
public String replaceAll(String, String)
public String toLowerCase()
public String toUpperCase()
public String trim()
void getBytes(int srcBegin, int srcEnd,
  byte[] dst, int dstBegin)
void getChars(int srcBegin, int srcEnd,
  char[] dst, int dstBegin)
public static String valueOf(char)
public static String valueOf(int)
public static String valueOf(long)
public static String valueOf(char[])
public static String copyValueOf(char[])
public static String valueOf(float)
public static String valueOf(double)
public static String valueOf(boolean)
public static String valueOf(char[], int, int)
public static String copyValueOf(char[],int, int)

Clase StringBuffer y StringBuilder

Clase StringBuffer Clase StringBuilder
public StringBuffer()
public StringBuffer(int)
public StringBuffer(String)
public StringBuffer(CharSequence)

public int length()
public char charAt(int)
public String substring(int)
public String substring(int, int)
public CharSequence subSequence(int,int)
public String toString()

public int indexOf(String)
public int indexOf(String, int)
public int lastIndexOf(String)
public int lastIndexOf(String, int)

public int codePointAt(int)
public int codePointBefore(int)
public int codePointCount(int, int)
public int offsetByCodePoints(int, int)

public int capacity()
public void ensureCapacity(int)
public void setLength(int)
public void trimToSize()
public void getChars(int, int, char[], int)
public StringBuffer append(String)
public StringBuffer append(StringBuffer)
public StringBuffer append(char[])
public StringBuffer append(char[], int, int)
public StringBuffer append(boolean)
public StringBuffer append(char)
public StringBuffer append(int)
public StringBuffer appendCodePoint(int)
public StringBuffer append(long)
public StringBuffer append(float)
public StringBuffer append(double)

public StringBuffer insert(int, char[], int,int)
public StringBuffer insert(int, String)
public StringBuffer insert(int, char[])
public StringBuffer insert(int, boolean)
public StringBuffer insert(int, char)
public StringBuffer insert(int, int)
public StringBuffer insert(int, long)
public StringBuffer insert(int, float)
public StringBuffer insert(int, double)

public StringBuffer delete(int, int)
public StringBuffer deleteCharAt(int)

public void setCharAt(int, char)
public StringBuffer replace(int, int, String)
public StringBuffer reverse()
...

Literales String

Ejemplos
  • es la única clase cuyos objetos pueden presentarse en forma literal;

  • su formato es una secuencia de caracteres de cualquier longitud encerrados entre dobles comillas

"<caracter>..."
  • son objetos de la clase String cuya evaluación devuelve la dirección del objeto al que representan;

  • además, es la única clase que disfruta de un operador (+) para la concatenación de cadenas de caracteres y combinado con cualquier tipo.

int longitud = "caracteres".length();
String cadena = new String("caracteres");
boolean falso = cadena == "caracteres";
boolean cierto = cadena.equals("caracteres");
boolean tambien = "caracteres".equals(cadena);
StringBuffer buffer = new StringBuffer(cadena);
buffer.insert(0, "de ").insert(0, "cadena ");
boolean si = ("cadena de " + cadena).
    contentEquals(buffer);
String serie = (0+1)+", "+(1+1)+","+(2+1)+".";
Aplicaciones

Clases de Recubrimiento

Clases de Recubrimiento Clase Character
  • Aglutinan funciones de conversión entre los tipos primitivos y las correspondientes cadenas de caracteres junto con algunas otras funciones auxiliares particulares de cada tipo primitivo.

class Character {
  Character(char)
  char charValue()
  int compareTo(Character)
  int hashCode()
  public static String toString(char)
  public static char[] toChars(int)
  public static boolean isLowerCase(char)
  public static boolean isUpperCase(char)
  public static boolean isTitleCase(char)
  public static boolean isDigit(char)
  public static boolean isDefined(char)
  public static boolean isLetter(char)
  public static boolean isLetterOrDigit(char)
  public static char toLowerCase(char)
  public static char toUpperCase(char)
  public static char toTitleCase(char)
  public static int getNumericValue(char)
  public static boolean isSpace(char)
  public static boolean isSpaceChar(char)
  public static boolean isWhitespace(char)
  ...
}
Clase Integer
class Integer {
  public static final int MIN_VALUE;
  public static final int MAX_VALUE;
  public static final int SIZE;
  public Integer(int)
  public Integer(String)
  public byte byteValue()
  public short shortValue()
  public int intValue()
  public long longValue()
  public float floatValue()
  public double doubleValue()
  public String toString()
  public int hashCode()
  public int compareTo(Integer)
  ...
  ...
  public static String toString(int, int)
  public static String toHexString(int)
  public static String toOctalString(int)
  public static String toBinaryString(int)
  public static String toString(int)
  public static int stringSize(int)
  public static int parseInt(String, int)
  public static int parseInt(String)
  public static Integer valueOf(String, int)
  public static Integer valueOf(String)
  public static Integer valueOf(int)
  public static Integer getInteger(String)
  public static Integer getInteger(String,int)
  public static Integer getInteger(String,Integer)
  public static Integer decode(String)
  public static void getChars(int, int, char[])
}
Clase Boolean Ejemplos
class Boolean {
  public static Boolean FALSE
  public static Boolean TRUE
  public Boolean(boolean value)
  public Boolean(String s)
  public boolean booleanValue()
  public String toString()
  public boolean equals(Object obj)
  public int compareTo(Boolean b)
  public int hashCode()
  public static int compare(boolean x, boolean y)
  public static boolean getBoolean(String name)
  public static int hashCode(boolean value)
  public static boolean logicalAnd(boolean a, boolean b)
  public static boolean logicalOr(boolean a, boolean b)
  public static boolean logicalXor(boolean a, boolean b)
  public static boolean parseBoolean(String s)
  public static Boolean valueOf(boolean b)
  public static Boolean valueOf(String s)
  public static String toString(boolean b)
}
public Fecha(String cadena) {
  dia = Integer.parseInt(
    cadena.substring(0, cadena.indexOf("/")));
  cadena = cadena.substring(
    cadena.indexOf("/") + 1, cadena.length());
  mes = Integer.parseInt(
    cadena.substring(0, cadena.indexOf("/")));
  cadena = cadena.substring(
    cadena.indexOf("/") + 1, cadena.length());
  año = Integer.parseInt(cadena);
}

public String toString() {
  return dia + "/" + mes + "/" + año;
}
...

Enumerados

Enumerados Ejemplos
  • Son clases que limitan la creación de objetos a los enumerados explícitamente en la implementación de la clase

    • la única limitación respecto a la implantación de una clase normal es que, si incorporan constructores, deben ser privados para evitar la creación de nuevos objetos distintos a los ofertados por la implementación

    • donde cada <enumeradoX> es implícitamente una referencia a un objeto de la calse con modificadores public static final

    • la sentencia switch acepta expresiones de clase enumerado y, en tal caso, las posibles constantes de cada clausula case serán las referencias a los objetos especificados en el enumerado

  • El enumerado/clase Planeta responsable de su posición, velocidad, …​ con únicamente 8 objetos mutables con atributos y métodos

  • El enumerado/clase Mes responsable de su número máximo de días (28, 30 ó 31) y los literales en varios idiomas (“Enero”, “January”) con únicamente 12 objetos inmutables con atributos y métodos

  • El enumerado/clase Color responsable de nada con únicamente 2 objetos inmutables (vacíos) sin atributos ni métodos

Enumerado Clase con static
enum <Enumerado> {
  <enumerado1>[(<argumentos>)],
  ...
  <enumeradoN>[(<argumentos>)];

  <definiciónAtributos>

  private <Enumerado> ([<parametros>]) {
    ...
  }

  <definiciónMétodos>

  public void <metodo> () {
    ...
    switch(this){
      case <enumerado1>:
      case <enumerado2>:
      ...
        <sentencia>;
        break;
      default:
        <sentencia>;
    }
  }
}
class <Enumerado> {
  public static final <Enumerado> <enumerado1> = new <Enumerado>([<argumentos>]);
  ...
  public static final <Enumerado> <enumeradoN> = new <Enumerado>([<argumentos>]);

  <definiciónAtributos>

  private <Enumerado> ([<parametros>]) {
    ...
  }

  <definiciónMétodos>

  public void <metodo> () {
    ...
    if(this == <enumerado1> || this== <enumerado2>) {
      <sentencia>;
    } else {
      <sentencia>;
    }
  }
}
Métodos implícitos Sintaxis
  • devuelve la posición del enumerado dentro de la secuencia expresada en la implementación

  • devuelve el identificador del enumerado;

  • devuelve un vector de referencias con la dirección de todos los objetos enumerados

    • la sentencia for acepta tablas de objetos enumerados en su formato iterador como tablas de objetos de clases

class <Enumerado> {
    public int ordinal()
    public String name()
    public static <Enumerado>[] values()
    ...
}

class App {
  public static void main(String[] args){
    Console console = new Console();
    for(<Enumerado> enum : <Enumerado>.values()) {
      console.writeln(
        "" + enum.ordinal() + ". " + enum.name());
    }
  }
}
class Color {
  RED,
  YELLOW;
}

class App {
  public static void main(String[] args){
    String string = "";
    for(Color color : Color.values){
      string += (color.ordinal() + 1) + ". " + color.name();
    }
    new Console().writeln(string);
  }
}

Programación Orientada a Objetos

Relación de Herencia

Transmisión
  • La herencia en todos los ámbitos (derecho, biología, …​) tiene connotaciones de transmisión

  • En Programación Orientada a Objetos es la transmisión de todos los miembros (atributos y métodos públicos y privados) de una clase a otra.

  • Terminología:

    • clase base para la que transmite y clase derivada a la que recibe la transmisión

    • paralela a los árboles genealógicos: padre, hija, nieta …​

    • superclase y subclases en desuso

Transmision
Colaboración entre objetos Ejemplo
  • Las relaciones de composición, asociación y dependencia son relaciones binarias que devienen de la colaboración entre objetos: envío de mensajes entre objetos

  • La relación de herencia:

    • es una relación binaria entre clases

    • si existe una relación de herencia, no es necesario que exista una colaboración entre los objetos de sus clases aunque tampoco lo impide

    • por tanto, los objetos de las clases de una relación de herencia son, a priori, independientes.

  • La clase Persona hereda de la clase Animal

    • en una aplicación sobre la evolución de las especies, sus objetos no colaboran

    • en una aplicación para la gestión de una granja, sus objetos sí colaboran

Tipos de Relación de Herencia Ejemplos
  • Herencia simple: cuando una clase derivada hereda de una única clase base.

  • Herencia múltiple: cuando una clase derivada hereda de varias clases base.

HerenciaSimple
HerenciaMultiples

Jerarquías de Clasificación

Definición Ejemplos
  • Una jerarquía por grado de clasificación es aquélla donde cada nodo (clases) de la jerarquía establece un dominio de elementos (conjuntos de objetos de la clase) incluido en el dominio de los nodos padre e incluye a los dominios de cada nodo hijo

    • La relación de herencia permite establecer jerarquías por grado de clasificación

  • Características

    • Eminentemente subjetivas

      • Ej. paciente de un hospital: publica/privada, por especialidad,…​

    • Contemplan elementos que son dificilmente categorizables

      • Ej. Ornotorrinco, pingüino, mula,…​

    • Dificultad para establecer una clasificación "perfecta"

    • Esqueleto fundamental de un programa junto con la jerarquía de composición

  • Reglas de Construcción

    • Regla de Generalización/Especialización: cuando existen unas características específicas de un subconjunto de elementos de un determinado conjunto más amplio, que pese a que mantienen las características esenciales e identificativas del conjunto al que pertenecen, también son lo suficientemente relevantes como para ser rasgos distintivos de dicho subconjunto de elementos.

    • Regla ¿Es un? (ISA): responder afirmativamente que un objeto de la clase hija es un objeto de la clase padre.

height32
Jerarquia

Herencia por extensión

Sintaxis Ejemplo
  • Mediante la palabra reservada extends

    • No permite herencia múltiple

class <claseDerivada> extends <claseBase> {
   ...
}
class Abuela {
  ...
}
class Padre extends Abuela {
  ...
}
class Hija extends Padre {
  ...
}
HerenciaExtencion

Especialización por adición

Atributos Métodos Constructores
  • Los atributos añadidos en la clase hija tienen las mismas reglas sintácticas y semánticas que en una clase que no sea derivada

  • Los métodos añadidos en la clase hija tienen las mismas reglas sintácticas y semánticas que en una clase que no sea derivada

    • excepto que NO tienen acceso a los atributos y métodos privados transmitidos desde la clase padre, si no es a través de los métodos públicos transmitidos desde la clase padre

      • Esto permite la contención del mantenimiento, dado que, si se modifica la implantación de la clase padre, no repercute sobre la implantación de la clase hija y se obtiene un mínimo acoplamiento entre ambas clases

  class <Clase> {

    public <Clase>({ <parametro> }* ){
      super( { <expresion> }*);
      ...
    }
  }
  • Mediante super, donde debe ser la primera sentencia de los constructores de la clase derivada y sus argumentos deben coincidir en número y tipo con la lista de parámetros de algún constructor público o protegido de la clase padre

    • Se puede omitir para el caso del constructor de la clase padre con una lista vacía de parámetros

Implicaciones sobre los objetos Ejemplo
  • Los objetos de la clase padre NO sufren ninguna alteración por la presencia de clases derivadas

  • Los objetos de la clase hija:

    • tienen todos los atributos transmitidos desde la clase padre junto con los atributos añadidos en la clase hija;

    • responden a mensajes que corresponden con los métodos públicos transmitidos desde la clase padre junto con los métodos públicos añadidos en la clase derivada;

HerenciaExtencion2
Miembros protegidos

Cuando la clase padre no transmite los métodos públicos necesarios para manipular los atributos privados transmitidos desde la clase padre en los métodos añadidos en la clase hija

  • Visibilidad publica añadiendo dichos métodos públicos a la clase padre NO es solución puesto que rompe el principio de encapsulación ya que, para la implantación de una clase hija, los objetos de la clase padre dan a conocer más allá de lo que se les solicitaba previamente a la existencia de la clase derivada.

  • Visibilidad protegida (protected), donde los miembros (atributos y/o métodos) son accesibles en la implantación de la clase y en cualquier clase derivada.

  • Atributos protegidos Dentro del cuerpo de los métodos de la clase derivada se tiene acceso a los atributos protegidos heredados, a los atributos añadidos, a los parámetros del método y a las declaraciones locales, ley flexible de Demeter

    • Implicación: desbordamiento del mantenimiento dado que si se modifica la implantación de la clase padre SI repercute sobre la implantación de la clase hija y se obtiene un máximo acoplamiento entre ambas clases

  • Métodos get/set protegidos son métodos para obtener el valor y asignar un valor a los atributos privados transmitidos desde la clase padre, posibilitando cualquier manipulación por parte de la clase hija futura;

    • Implicación: contención del mantenimiento dado que si se modifica la implantación de la clase padre no repercute sobre la implantación de la clase hija y se obtiene un mínimo acoplamiento entre ambas clases

Especialización por redefinición

  • Donde la cabecera del método es exactamente igual a la cabecera del método no privado de la clase padre, excepto su visibilidad, que puede ampliarse. En caso contrario, sería sobrecarga y no redifinición

  • Sus implicaciones son:

    • se anula la transmisión del método de la clase padre;

    • los objetos de la clase padre responden al mensaje con el comportamiento dado en la clase padre;

    • los objetos de la clase hija responden al mensaje con el comportamiento dado en la clase hija;

ListaCentinela
Referencia super
  • super, en la implantación de cualquier clase derivada, es una referencia constante que guarda la dirección del objeto que recibe el mensaje correspondiente al método que se está redefiniendo, pero con el comportamiento de la clase padre

    • Su utilidad será para la reutilización del método de la clase padre, anulado en la transmición, desde la redefinición del método de la clase hija

Conjunto

Clase Object

  • Toda clase "no derivada" explícitamente hereda implícitamente de la clase predefinida Object

    • Proporciona un conjunto de métodos comunes a todas las clases, algunos de ellos susceptibles de ser redefinidos en cualquier clase de la manera oportuna.

      • además, métodos para la sincronización de programas concurrentes y para usar la reflexión

class Object {
  public boolean equals(Object)
  public String toString()
  public int hashCode()
  protected Object clone()
  protected void finalize()
  ...
}

Clases Abstractas

Clases Concretas Clases Abstractas
  • Surgen de la descripción de los atributos y métodos que definen el comportamiento de un cierto conjunto de objetos homogéneos

  • Son clases NO instanciables que surgen del factor común del código de otras clases con atributos comunes, métodos comunes y/o cabeceras de métodos comunes sin definición.

height32
  • donde los métodos abstractos no pueden ser private.

Ejemplos

En un dispensador NO acotado se pueden meter o sacar elementos sin limitación para el número de elementos; una pila es un dispensador con política LIFO; una cola es una dispensador con política FIFO

Dispensador
Ejemplos
abstract class DispensadorNoAcotado {
  protected Nodo entrada;
  protected DispensadorNoAcotado(){
    entrada = null;
  }

 public void meter(Intervalo intervalo){
   entrada = new Nodo(null, intervalo, entrada);
 }

 public abstract Intervalo sacar();

 public boolean vacio(){
   return entrada == null;

 }
}
class PilaNoAcotada extends DispensadorNoAcotado {
  public Intervalo sacar() {
    Intervalo intervalo = entrada.getIntervalo();
    entrada = entrada.getSiguiente();
    return intervalo;
  }
}

class ColaNoAcotada extends DispensadorNoAcotado {
  private Nodo salida;
  public ColaNoAcotada() {
    salida = null;
  }
  public void meter(Intervalo intervalo) {
    boolean vacio = this.vacio();
    super.meter(intervalo);
    if (vacio) {
      salida = entrada;
    }
}

public Intervalo sacar() {
  Intervalo intervalo = salida.getIntervalo();
  if (salida.getAnterior() == null) {
    entrada = null;
    salida = null;
  } else {
    salida = salida.getAnterior();
    salida.setSiguiente(null);
  }
  return intervalo;
  }
}
  • Posibilidades:

    • una clase abstracta puede ser hija de otra clase abstracta porque se especializa (añadiendo atributos y/o métodos y/o redefiniendo métodos) pero NO redefine todos los métodos abstractos transmitidos y/o añade algún método abstracto;

Alumno
  • una clase abstracta puede ser hija de una clase concreta si en su especialización añade algún método abstracto

persona
Ejemplo:
  • Un método no abstracto de una clase abstracta puede definirse apoyándose en métodos abstractos entendiendo que será un código que se transmite hasta clases concretas que redefinen los métodos abstractos;

class Cubo extends Solido {
  private double lado;
  public double volumen() {
    return Math.pow(lado, 3);
  }
}

class Esfera extends Solido {
  private double radio;
  public double volumen() {
    return 4.0 / 3.0 * Math.PI * Math.pow(radio, 3);
  }
}
abstract class Solido {
  private double densidad;
  public double peso() {
    return densidad * this.volumen();
  }
  public abstract double volumen();
}

Herencia por Implementación

Interfaces Ejemplo
  • Son clases abstractas puras que no contienen ningún atributo ni la definición de ningún método, sólo contienen métodos abstractos. Puede ser clases padre de clases u otros interfaces.

interface <interfazBase> {
    <cabeceraMetodo1>;
    
    <cabeceraMetodoN>;
}

[abstract] class <claseDerivada> implements <interfazBase> {
    
}

interface <interfazDerivado> extends <interfazBase> {
    
}
  • donde todos los métodos del interfaz son públicos.

Ejemplo

Un dispensador NO acotado es un dispensador implantado con listas dinámicas; un dispensador acotado es un dispensador implantado con vectores

DispensadorHerencia

Ejemplos

interface Dispensador {
  void meter(Intervalo elemento);

  Intervalo sacar();

  boolean vacio();

}

abstract class DispensadorNoAcotado
        implements Dispensador {
 
  // expuesto anteriormente
}
abstract class DispensadorAcotado implements Dispensador {

  protected Intervalo[] elementos;
  protected int cuantos;
  protected int siguiente;

  protected DispensadorAcotado(int tamaño) {
    elementos = new Intervalo[tamaño];
    cuantos = 0;
    siguiente = 0;
  }

  public void meter(Intervalo intervalo) {
    cuantos++;
    elementos[siguiente] = intervalo;
    siguiente++;
}
  public boolean vacio() {
    return cuantos == 0;
}
public boolean lleno() {
  return cuantos == elementos.length;
}
  }
  class PilaAcotada extends DispensadorAcotado {

public PilaAcotada(int tamaño) {
  super(tamaño);
}
public Intervalo sacar() {
  cuantos--;
  siguiente--;
  return elementos[siguiente];
  }
}
class ColaAcotada extends DispensadorAcotado {
  private int inicio;
  public ColaAcotada(int tamaño) {
    super(tamaño);
    inicio = 0;
  }

public void meter(Intervalo intervalo) {
  super.meter(intervalo);
  if (siguiente == elementos.length)
    siguiente = 0;
}

public Intervalo sacar() {
  cuantos--;
  Intervalo intervalo = elementos[inicio];
  inicio = (inicio + 1) % elementos.length;
  return intervalo;
}
Ejemplo
  • Un interfaz NO puede heredar de una clase de ninguna manera, pero SI puede heredar de otro interfaz por extensión

  • Una clase SI puede heredar de una clase por extensión o de un interfaz por implementación

  • La herencia por extensión NO disfruta de herencia múltiple, pero la herencia por implementación SI disfruta de herencia múltiple

class <claseDerivada>
  extends <claseBase>
  implements <interfaz1>, , <interfazN> {
  
}
interface <interfazDerivado>
  extends <interfaz1>, , <interfazN> {
  
}

Limitaciones de la Herencia

  • Clases final no permiten ningún tipo de herencia posterior.

final class <clase> {
  
}
  • Metodos final no permiten ningún tipo de redefinición posterior.

class <clase> {
  
  final <metodo>
  
}
  • Los enumerados son siempre final.

  • Un enumerado NO pueden heredar de una clase por extensión, pero SI puede heredar de un interfaz por implementación.

Beneficios de la Herencia

  • Integridad de la Arquitectura del Software

    • La herencia favorece la comprensión de la arquitectura del software.

    • La jerarquía de clasificación de las clases establece los niveles de generalización que reducen significativamente el número de clases al estudiar en un diseño.

X
X2
  • Reusabilidad del código

    • Utilización del código de la clase padre previamente escrito, probado y documentado

    • No es necesario duplicar código similar,todo el código común se "factoriza" en la clasee padre.

Polimorfismo

Definición Ejemplo
  • Término de origen griego que significa "muchas formas".

  • Una persona puede pagar con tarjeta o con efectivo

  • Una empresa de transporte realiza ventas de billetes por ventanilla o a travéz de una maquina

  • Un sistema operativo imprime a travéz de drivers de impresora para cada modelo

  • Un navegador muestra textos,imagenes,videos,…​,con muy diversos formatos

  • no se contempla que algo cambie de formas

  • no se contempla que algo sea dos cosas a la vez

  • Una persona ed ventanilla NO se convierte en máquina exprendedora

  • Una persona NO es a la vez una máquina exprendedora

  • Simplemente, un billete lo puede vender una persona o una máquina exprendedora en cada momento que se vende un billete

Definición Ejemplo:
  • El polimorfizmo es una relajación del sistema de tipos, de tal manera que una referencia a una clase (atributo,parámetro o declaración local o elemento de un vector) acepta direcciones de objetos de dicha clase y de sus clases derivadas (hija,nieta,…​).

    • Por tanto:

      • el polimorfizmo exije la existencia de una jerarquía de clacificación;

      • las jerarquías de clasificación NO exigen tratamientos polimòrficos;

En un punto dado, existen listas, en otro punto, existen conjuntos y, en otro punto, pueden existir indiferentemente listas o conjuntos

Lista2
height32
Ejemplo:
  • donde un objeto se crea de una clase y siempre será de esa clase mientras que la referencia coleccion puede tener, en un momento dado, una dirección de un objeto lista o de un objeto conjunto

  • con la incorporación del polimorfismo, tiene sentido declarar referencias a clases abstractas con la intención de almacenar direcciones de objetos de clases concretas derivadas, NO de clases abstractas que no son instanciables;

A lo largo de la historia, en este mundo existe la jerarquía de personas: mujeres y hombres. Pero en ciertos momento y en ciertos países, no existe polimorfismo: el lugar de una mujer no lo puede ocupar un hombre y el de un hombre no lo puede ocupar una mujer. Mientras que, en otros momentos u otros países, el lugar de una persona es indiferentemente ocupado por una mujer o un hombre.

Persona2

height32

Comportamiento: Limitación:
  • donde no se contempla que una mujer se convierta en hombre o un hombre en mujer; ni se contempla que alguien sea mujer y hombre a la vez; lo único que se contempla es que una referencia a persona apunte a un objeto de la clase mujer u hombre

cuando se lanza un mensaje a un objeto a travéz de una referencia polimorfica se ejecuta el método prescrito en la clase del objeto que recibe el mensaje

  • Ejemplo:

En un punto dado, existen listas, en otro punto,existen conjuntos y, en otro punto, pueden existir indiferentemente listas o conjuntos

height32

cuando se lanza un mensaje a un objeto a travéz de una referencia polimorfica, éste debe estar contemplando en el interfaz de clase de la que se declaró la referencia sin contemplar los posibles métodos añadidos en la clase del objeto apuntado.

  • Ejemplo:

En un punto dado, existen listas, en otro punto,existen conjuntos y, en otro punto, pueden existir indiferentemente listas o conjuntos

height32

Formalización

Enlace: Ejemplo:
  • es la asociación entre un elemento de un lenguaje de programación y una de sus características;

  • una variable y su nombre, su valor, su dirección, su tipo,…​; una constante y su nombre, su valor, su dirección, su tipo,…​; una expreción y su número de operadores,su valor evaluado, su tipo,…​

Tipo de Enlaces: Ejemplo:

Enlace estático: aquel enlace que se puede resolver analizando el código, o sea, en tiempo de compilación;

una variable y su nombre, su tipo,…​; una constante y su nombre su valor, su tipo,…​;una expreción y su número de operadores, su tipo,…​

Enlase dinámico: aquel enlace que NO se puede resolver analizando el código sino que se resuelve en tiempo de ejecución;

una varuiable y su valor,…​; una expreción y su valor evaluado

Polimorfizmo: Ejemplos
  • es un enlace dinámico entre una referencia y una clase de objeto apuntado por la referencia;

Lista coleccion;

 coleccion 
Persona persona;

 persona 
height32

Polimorfismo vs sobrecarga

Sobrecarga Ejemplos

es un enlace estático entre un mensaje y el método que se ejecuta;

class A {
  public void m()
  public void m(A a)
  public void m(B b)
  public A m(B b, C c)
  public B m(A a, C c)
}
class B {
}
class C {
}


A a;
B b;
C c;
a.m(b, c).m();
b = a.m(a, c);

Beneficios del Polimorfismo

Abstracción Extensibilidad
“Entonces es el receptor del mensaje el que determina cómo se interpretará el mensaje y no lo hará el emisor. El emisor sólo necesita conocer qué comportamiento puede desarrollar el otro objeto, no qué clase de objeto cree que es y, por tanto, qué método realiza en cada instante el comportamiento. Esto es una herramienta extremadamente importante para permitirnos desarrollar sistemas flexibles. De esta manera, sólo tenemos especificado qué ocurre pero no cómo ocurrirá. Mediante esta forma de delegar qué ocurrirá, se obtiene un sistema flexible y resistente a las modificaciones”
— Jacobson (creador de los Casos de Uso)
1992
“Emplear las consultas de tipo durante la ejecución para implantar un enunciado de conmutación – estructura de control de flujo CASE o IF-THEN-ELSE encadenados – en un campo de tipo destruye toda la modularidad de un programa y anula los objetivos de la programación orientada a objetos. También es propensa a errores; […] La experiencia demuestra que los programadores que se formaron con lenguajes como Pascal o C encuentran esta trampa muy difícil de resistir. Una razón es que este estilo requiere menos premeditación […]; en este contexto, semejante falta de premeditación muchas veces no es más que una chapuza.”
— Stroustrup (creador de C++)
1993
  • !!! No se puede preguntar por la clase de un objeto polimórfico!!!

Converción de Tipos

Conversión ascendente (upcast) Conversión descendente (downcast)

cuando se transforma una dirección de un objeto de una clase a una dirección del objeto pero de una clase ascedente (padre, abuela, …) ;

cuando se transforma una dirección de un objeto de una clase a una dirección del objeto pero de una clase derivada (hija, nieta, …) ;

Ejemplo
  • Conversión implícita: por conversión ascendente cuando se asigna una dirección de un objeto de una clase a una referencia declarada a una clase ascendente;

  • Conversión explícita: por conversión descendente a través del operador de conversión de tipos (cast);

(<tipo>) <direccion>
Lista lista = new Lista();
Conjunto conjunto = new Conjunto()
Lista coleccion = new Conjunto();
Conjunto resultado;
resultado = conjunto.interseccion(coleccion); // ERROR
resultado = conjunto.interseccion((Conjunto) coleccion);
resultado = coleccion.interseccion(conjunto); // ERROR
resultado = ((Conjunto) coleccion).interseccion(conjunto);
((Conjunto) lista).interseccion(conjunto); // ERROR DE
                                          // EJECUCION
lists
dispenser
menus

Programación Modular

Modularidad Niveles
  • Proceso de descomposición de un sistema (en nuestro caso, software) en un conjunto de módulos poco acoplados (independientes) y altamente cohesivos (con significado propio);

  • Clases, módulos elementales en los que se descompone un programa/ biblioteca/ aplicación

  • Paquetes, agrupan un conjunto de clases estrechamente relacionadas entre sí

  • Bibliotecas, agrupan un conjunto de paquetes que proporcionan un conjunto de funcionalidades genéricas

  • Aplicaciones, agrupan un conjunto de paquetes y bibliotecas, para proporcionar un conjunto de funcionalidades específicas

Beneficios
  • Reusabilidad, permiten fomentar la reutilización en muchos programas diferentes

  • Encapsulación, permiten ocultar la implementación del módulo de su interfaz, lo que redunda en una mayor capacidad para sustituir un módulo por otro con la misma funcionalidad, facilitando el mantenimiento de las aplicaciones

  • Espacios de nombres, permiten resolver colisiones entre los nombres de los identificadores usados en cada módulo

  • Arquitectura, permiten organizar los componentes de los que se compone el programa y las relaciones entre estos elementos

  • Desarrollo en equipo, permiten separar responsabilidades entre distintos grupos de desarrolladores, que pueden implementar y probar cada módulo independientemente y en paralelo

Jerarquía de Paquetes

Nombres de paquetes Ejemplos
  • Permite agrupar un conjunto de clases, interfaces y enumerados, junto con archivos de recursos (como textos, imágenes, sonidos, …​) en paquetes

    • Un paquete puede contener, a su vez, otros paquetes, lo que produce una organización jerárquica y debe situarse en un directorio del sistema operativo, de acuerdo a la jerarquía de paquetes, cuya raíz puede estar en cualquier directorio

    • Cada paquete tiene un nombre, que comienza por minúsculas y que corresponde con la jerarquía de directorios del sistema operativo

    • El nombre del paquete debe ser único (como los directorios dentro de un directorio), lo cual es problemático si puede usarse en cualquier lugar del mundo, en cuyo caso, la ruta del nombre de los paquetes deberían comenzar con un nombre de dominio de Internet de la institución de desarrollo, en orden inverso

  <paquete1>.<paquete2>. ... .<paqueteN>
  pooa.util.pooa.ter.modelos
height32
  es.upm.eui.lpsi.pooa.util
height32
Clasificadores en paquetes Ejemplo
  • Para añadir una clase, interface y/o enumerado a un paquete (clasificadores), hay que situar su fichero fuente en el directorio del paquete y, en la primera línea del código (sin contar los comentarios), escribir la sentencia de declaración de paquete package, para indicar que el clasificador pertenece a ese paquete

    • En un fichero fuente sólo puede aparecer una declaración de paquete

    • Si en un fichero fuente no se especifica ningún paquete, la clase pertenecerá a un paquete sin nombre por defecto;

      • Esto puede ser útil en el caso de aplicaciones con pocas clases

 package <paquete1>.<paquete2>. ... <paqueteN>;
height32
  package pooa.ter.modelos;

  class MTablero {
    ...
  }

Visibilidad de Clasificadores

  • La visibilidad de las clases de un paquete es:

    • Las clases declaradas public son accesibles desde cualquier código exterior al paquete

      • Si hay una clase publica, entonces el nombre del fichero debe coincidir con el nombre de esa clase, y con extensión .java

      • En un fichero fuente puede haber varias declaraciones de clases, pero como máximo una de ellas puede ser public;

        • La recomendación es disponer los clasificadores en distintos ficheros, siendo excepcional y poco recomendado para alguna clase auxiliar

    • Las clases NO declaradas public sólo son accesibles solo desde el código de ese paquete (tampoco desde sus subpaquetes);

  • MTablero.java

package pooa.ter.modelos;

public class MTablero {
 ...
}
  • CAbrir.java

package pooa.ter.controladores;

public class CAbrir {
  ...
}
class CPoner {
  ...
}
class CMover {
  ...
}

Importación de Clasificadores

Acceso a las clases
  • acceder a las clases con visibilidad pública de un paquete desde la implementación de una clase de otro paquete, requiere la importación de dichas clases

  • acceder a las clases del mismo paquete no tiene ninguna implicación

  • acceder a las clases con visibilidad de paquete desde una clase de otro paquete está prohibido

  • acceder a las clases del paquete por defecto desde una clase de otro paquete está prohibido

Importación explícita Ejemplo
  • Para acceder a una clase con visibilidad pública declarada en un paquete desde una clase de otro paquete, debe usarse la sentencia de importación import de un único tipo, especificando el nombre completamente calificado de la clase a la que se desea acceder

    • Deben aparecer en un fichero fuente después de la declaración de paquete y antes de cualquier clasificador

package <paqueteX>.<paqueteY>. ... .<paqueteZ>;

import <paquete>.<Clasificador>;

class <Clase> {
  ...
}
package pooa.ter.controladores;

import pooa.ter.modelos.MTablero;
import pooa.ter.modelos.MTurno;
import pooa.ter.vistas.VTablero;
import pooa.ter.vistas.VTurno;

public class CAbrir {
  private MTablero mTablero = new MTablero();
  private VTablero vTablero = new VTablero(mTablero);
  private MTurno mTurno = new MTurno();
  private VTurno vTurno = new VTurno(mTurno);
  ...
}
Importación bajo demanda Ejemplo
  • Cuando se usan muchas clases de un mismo paquete, se pueden importar todas las clases del paquete, mediante la sentencia de importación import de tipos bajo demanda con la notación *

import <paquete1>. ... <paqueteN>.*;
package pooa.ter.controladores;

import pooa.ter.modelos.*;
import pooa.ter.vistas.*;

class CMover {
  private MTablero mTablero;
  private VTablero vTablero;
  private MTurno mTurno;
  private VTurno vTurno;
  ...
}
Importación implícita Ejemplo
  • El código fuente de cualquier fichero de un paquete importa implícitamente el resto de su propio paquete, por lo que todas las clases definidas en un paquete están disponibles para todas las clases de ese mismo paquete

package pooa.ter.controladores;

import pooa.ter.controladores.CPoner; // innecesario

public class CAbrir {
  ...
  CPoner cPoner = new CPoner(mTablero, mTurno);
  CMover cMover = new CMover(mTablero, mTurno);
  ...
}
Colisión de nombres Ejemplo
  • Es un error importar el mismo nombre de clase de dos paquetes diferentes usando importaciones individuales de clase y/o bajo demanda

import java.util.Date;
import java.sql.Date; // Error
import java.util.*;
import java.sql.*;
...
  Date fecha = new Date(); // Error
...
Resolución de Colisión de nombres Ejemplo
  • Para resolver colisiones al utilizar clases con el mismo nombre que pertenecen a paquetes distintos, se debe usar el nombre completamente calificado de la clase en todas sus ocurrencias


java.util.Date fechaUtil = new java.util.Date();
java.sql.Date fechaSql = new java.sql.Date();

Visibilidad de Miembros

  • Los miembros declarados public son accesibles desde cualquier código exterior al paquete

  • Los miembros declarados private sólo son accesibles desde el código de esa clase

  • Los miembros declarados protected son accesibles desde el código de esa clase, de sus clases derivadas de cualquier paquete, y del resto de clases de ese paquete (no de sus subpaquetes)

  • Los miembros que no especifican ningún modificador de acceso sólo son accesibles desde las clases de ese paquete (no de sus subpaquetes)

  • Modificador

    • public

    • protected

    • ninguno

    • private

  • Desde su clase

    • Si

    • Si

    • Si

    • Si

  • Desde su paquete

    • Si

    • Si

    • Si

    • No

  • Desde sus subclases

    • Si

    • Si

    • No

    • No

  • Desde el resto

    • Si

    • No

    • No

    • No

Paquetes y Herencia

  • Un método se puede redefinir en una clase derivada sólo si dicho método de la clase base es accesible desde la clase derivada

    • Si el método no es accesible, el método de la clase derivada no redefine el método de la clase base, incluso aunque tenga la misma cabecera

  • Cuando se invoca un método, el sistema tiene que considerar en tiempo de ejecución la accesibilidad de dicho método para decidir qué implementación del método se debe invocar

Ejemplo
package package1;

public class BaseClass {

  public void writeln() {
    this.privateMehtod();
    this.packageMethod();
    this.protectedMethod();
    this.publicMethod();
  }

  private void privateMehtod() {
    Console.getInstance().writeln( "privateMehtod of BaseClass");
  }

  void packageMethod() {
    Console.getInstance().writeln( "packageMethod of BaseClass");
  }

  protected void protectedMethod() {
    Console.getInstance().writeln( "protectedMethod of BaseClass");
  }

  public void publicMethod() {
    Console.getInstance().writeln( "publicMethod of BaseClass");
  }

}
package package2;

import package1.BaseClass;

public class DerivatedClass extends BaseClass {

    private void privateMehtod() {
    Console.getInstance().writeln( "privateMehtod of DerivatedClass");
  }

  void packageMethod() {
    Console.getInstance().writeln( "packageMethod of DerivatedClass");
  }

  protected void protectedMethod() {
    Console.getInstance().writeln( "protectedMethod of DerivatedClass");
  }

  public void publicMethod() {
    Console.getInstance().writeln( "publicMethod of DerivatedClass");
  }

}
package app;

import package1.DerivatedClass;

class App {

  public static void main(String[] args) {
    new DerivatedClass().writeln();
  }
}
  • al ejecutar su método principal, se produciría la siguiente salida por pantalla:

privateMehtod of BaseClass
packageMethod of BaseClass
protectedMethod of DerivatedClass
publicMethod of DerivatedClass

API de J2SE

Biblioteca estandar (Application Programming Interface)
  • java.lang: clases básicas del lenguaje, este paquete es importado implícitamente por cualquier código

  • java.util: estructuras de datos y utilidades

  • java.io: acceso a ficheros

  • java.awt, javax.swing: interfaces gráficas de usuario

  • java.net: acceso a redes

  • java.sql: acceso a bases de datos

  • …​

height32
height32
height32
height32
height32
Aplicaciones

Programación con Excepciones

  • cuando se produce un error de ejecución en un programa, se interrumpe bruscamente la ejecución secuencial de sus instrucciones, es decir, no se ejecuta ninguna operación posterior a aquélla en la que se ha producido el error, y se eleva o lanza una excepción que representa ese error

  • por defecto, se muestra por pantalla un informe del error producido, y finaliza la ejecución del programa

Excepciones

  • los errores en tiempo de ejecución se gestionan con excepciones;

    • proporcionan una forma clara de indicar la existencia de posibles errores de ejecución, así como de comprobar la ocurrencia de dichos errores de ejecución sin oscurecer el código del programa

    • las excepciones se representan mediante objetos de clases que pertenecen a la siguiente jerarquía

    • cuando se produce una excepción se crea un objeto de la clase adecuada, dependiendo del tipo de error producido, que mantendrá la información sobre el error y proporcionará métodos para obtener dicha información

Excepciones
  • Clase Throwable:

    • la raíz de la jerarquía de clasificación y, por tanto, es la superclase de todas las excepciones. Métodos:

    • toString, devuelve un mensaje que informa de la excepción

    • printStackTace, imprime por la salida estándar los métodos que estaban en la pila de ejecución (llamadas anteriores a aquélla que produjo el error) cuando se produjo la excepción y la línea donde se produce la excepción.

      • Es el comportamiento por defecto cuando no se maneja la excepción.

  • Clase Error:

    • representa las excepciones graves que no deberían ser capturadas por un programa

      • java.lang.VirtualMachineError deriva de java.lang.Error

  • Clase Exception:

    • representa las excepciones normales que un programa podría capturar

  • Clase RuntimeException:

    • representa aquellas excepciones normales que NO es necesario capturar en un programa, se denominan no comprobadas

      • java.lang.ArithmeticException deriva de java.lang.RuntimeException, por división por cero

  • Clase IOException:

    • el resto de clases que heredan de la clase Exception representan aquellas excepciones que SI es necesario capturar en un programa, estas excepciones se denominan comprobadas

      • representan las excepciones comprobadas relacionadas con operaciones fallidas de entrada y salida,

        • java.io.FileNotFoundException deriva de java.io.IOException, al tratar de abrir en modo lectura un fichero inexistente

Gestión de excepciones

  • elevar la excepción: cuando una biblioteca o subsistema encuentra un error porque no se cumplen las condiciones de su uso

  • capturar la excepción: cuando una aplicación o biblioteca usa un recurso (ficheros, comunicaciones, bibliotecas, …​) que puede dar problemas, hay que capturarlos para solventar esos problemas

  • delegar la excepción:

    • cuando una aplicación o biblioteca usa un recurso (ficheros, comunicaciones, bibliotecas, …​) que pueden dar problemas, se le comunica a quien corresponda para que los resuelva

    • cuando una aplicación o biblioteca usa un recurso (ficheros, comunicaciones, bibliotecas, …​) que pueden dar problemas, hay que capturarlos para solventar en parte esos problemas y elevar otra excepción a quien corresponda para que resuelva el resto

Elevación de Excepciones

Sentencia throw
  • durante la ejecución de un método se puede elevar una excepción, para indicar que se ha producido un error de ejecución debido a alguna razón, lo que provoca la finalización brusca de su contexto de ejecución

  • para elevar una excepción se debe usar la siguiente sentencia:

  throw <expresión>;
  • donde la expresión debe evaluar a una referencia a Throwable

  • en un mismo método se pueden elevar, de forma alternativa, varias excepciones

Ejemplo Fraction.java
package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a1_arithmetic;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Antes");
    new FractionView().writeln(new Fraction(3, 0));
    Console.getInstance().writeln("Despues");
  }
  
}
Antes
Exception in thread "main" java.lang.ArithmeticException: El denominador no puede ser 0
  at Fraccion.<init>(Fraccion.java:10)
  at Aplicacion.main(Aplicacion.java:6)
package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a2_format;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Antes");
    new FractionView().writeln(new Fraction("2/a3"));
    Console.getInstance().writeln("Despues");
  }
  
}
Antes
Exception in thread "main" java.lang.NumberFormatException: Formato incorrecto
  at Fraccion.<init>(Fraccion.java:17)
  at Aplicacion.main(Aplicacion.java:6)
Cláusula throws
  • las únicas excepciones comprobadas que puede elevar un método son aquéllas cuyas clases se declaran en su cabecera mediante la siguiente cláusula:

<modificador> <tipo1> <nombreMétodo>({<tipo2> <parametro>, }+)
       throws {<claseExcepción1>,}+
  • como ya hemos visto, un método puede elevar excepciones no comprobadas sin necesidad de declarar sus clases en la cabecera, aunque puede ser conveniente por razones de documentación

class Fraction {
  ...
  public void read(String path) throws IOException {
  ...
    if (<error de apertura>) {
      throw new IOException("Error al leer el fichero " + path);
    }
    ...
  }
  ...
}

Captura de Excepciones

Excepciones no comprobadas Excepciones comprobadas
  • elevadas por un método pueden ser capturadas en ese mismo método o en cualquier método que, directa o indirectamente, lo haya invocado

  • si un método invoca otro método que eleva excepciones no comprobadas no es necesario que las capture, pero, en el caso de que se produzca la excepción, si ningún método captura la excepción, el programa termina bruscamente

  • si un método invoca otro método que eleva excepciones comprobadas, entonces es obligatorio que el método que invoca al otro capture dichas excepciones

Sentencia try/catch/finally
  • para capturar una excepción se debe usar la siguiente sentencia, donde se pueden omitir la claúsula catch o finally, pero no ambas:

try {
     <sentencia1>
     ...
     <sentenciaN>
}
[
   catch (<declaraciónExcepción1>) {
     <sentencia11>
     ...
     <sentencia1N1>
}
...
   catch (<declaraciónExcepciónM>) {
    ...
}
]
[ finally {
  ...
} ]
  • Bloque try:

    • indica las sentencias en cuya ejecución se desea capturar una excepción, en el caso de que ésta se produzca

    • cuando se produce una excepción en alguna de sus sentencias, se interrumpe bruscamente su ejecución

  • Bloque catch:

    • especifican las sentencias a ejecutar cuando se produzca una excepción dentro del bloque try

    • se debe especificar la clase de excepción que queremos capturar mediante la declaración de una excepción de esa clase

    • opcionalmente, se pueden especificar distintos bloques catch, para indicar distintos tratamientos para distintas clases de excepciones

    • es un error especificar más de un bloque catch para una misma clase de excepción;

  • Bloque finally:

    • se ejecuta siempre, después de la ejecución de try/catch

    • sirve para ejecutar un cierto código independientemente de si se produce o no la excepción, si se captura o no, o de cualquier otra circunstancia;

    • se suele usar para garantizar la liberación de recursos, por ejemplo, cerrar ficheros archivos abiertos, puertos de comunicaciones, etc.

Ejemplo Ejecución
package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a4_catch;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Inicio");
    try {
      Console.getInstance().writeln("Antes");
      new FractionView().writeln(new Fraction(3, 0));
      Console.getInstance().writeln("Después");
    } catch (ArithmeticException ex) {
      Console.getInstance().writeln("Error aritmetico");
      ex.printStackTrace();
    }
    Console.getInstance().writeln("Fin");
  }

}
Inicio
Antes
Error aritmetico
java.lang.ArithmeticException: El denominador no puede ser 0
      at Fraccion.<init>(Fraccion.java:10)
      at Aplicacion.main(Aplicacion.java:10)
Fin
package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a5_catchsFirst;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Inicio");
    try {
      Console.getInstance().writeln("Antes");
      new FractionView().writeln(new Fraction("3/0"));
      Console.getInstance().writeln("Después");
    } catch (ArithmeticException ex) {
      Console.getInstance().writeln("Error aritmetico");
      ex.printStackTrace();
    } catch (NumberFormatException ex) {
      Console.getInstance().writeln("Error de formato");
      ex.printStackTrace();
    }
    Console.getInstance().writeln("Fin");
  }

}
Inicio
Antes
Error aritmetico: El denominador no puede ser 0
Fin
package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a6_catchsSecond;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Inicio");
    try {
      Console.getInstance().writeln("Antes");
      new FractionView().writeln(new Fraction("3/a2"));
      Console.getInstance().writeln("Después");
    } catch (ArithmeticException ex) {
      Console.getInstance().writeln("Error aritmetico");
      ex.printStackTrace();
    } catch (NumberFormatException ex) {
      Console.getInstance().writeln("Error de formato");
      ex.printStackTrace();
    }
    Console.getInstance().writeln("Fin");
  }

}
Inicio
Antes
Error de formato: Formato incorrecto
Fin

Delegación de Excepciones

Delegación Ejemplo
  • si el método no captura una excepción, la propaga al método que lo invocó

    • si un método declara que eleva excepciones comprobadas, entonces no necesita capturar esas clases de excepciones que declara, cuando invoca métodos que elevan esas mismas clases de excepciones

Antes
Error aritmetico
java.lang.ArithmeticException: El denominador no puede ser 0
         at Fraccion.<init>(Fraccion.java:17)
         at Fraccion.crearFraccion(Fraccion.java:26)
         at Aplicacion.main(Aplicacion.java:14)
Fin
package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a7_nested;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Inicio");
    try {
      Console.getInstance().writeln("Antes");
      new FractionView().writeln(App.createFraction(3, 0));
      Console.getInstance().writeln("Después");
    } catch (ArithmeticException ex) {
      Console.getInstance().writeln("Error aritmetico");
      ex.printStackTrace();
    } catch (NumberFormatException ex) {
      Console.getInstance().writeln("Error de formato");
      ex.printStackTrace();
    }
    Console.getInstance().writeln("Fin");
  }

  public static Fraction createFraction(int numerator, int denominator) throws ArithmeticException {
    return new Fraction(numerator, denominator);
  }

}

Excepciones Polimorficas

  • cuando un método captura una excepción, sólo se ejecuta la primera sentencia catch en la que la referencia de la excepción producida encaje en la clase de excepción declarada en esa sentencia catch;

package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a8_polymorphic;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Inicio");
    try {
      Console.getInstance().writeln("Antes");
      new FractionView().writeln(App.createFraction(3, 0));
      Console.getInstance().writeln("Después");
    } catch (ArithmeticException ex) {
      Console.getInstance().writeln("Error aritmetico");
      ex.printStackTrace();
    } catch (Exception ex) {
      Console.getInstance().writeln("Error");
      ex.printStackTrace();
    }
    Console.getInstance().writeln("Fin");
  }

  public static Fraction createFraction(int numerator, int denominator) throws ArithmeticException {
    return new Fraction(numerator, denominator);
  }

}
Inicio
Antes
Error aritmetico : El denominador no puede ser 0
Fin
  • es un error de compilación tratar de capturar una excepción en una sentencia catch, que ya ha sido capturada previamente en otra sentencia catch;

package es.usantatecla.a5_units.a0_fraction.a5_exceptions.a9_polymorphic2;

public class App {

  public static void main(String[] args) {
    Console.getInstance().writeln("Inicio");
    try {
      Console.getInstance().writeln("Antes");
      new FractionView().writeln(App.createFraction("3/a2"));
      Console.getInstance().writeln("Después");
    } catch (ArithmeticException ex) {
      Console.getInstance().writeln("Error aritmetico");
      ex.printStackTrace();
    } catch (Exception ex) {
      Console.getInstance().writeln("Error");
      ex.printStackTrace();
    }
    Console.getInstance().writeln("Fin");
  }

  public static Fraction createFraction(String string) throws ArithmeticException, NumberFormatException {
    return new Fraction(string);
  }

}
  • los métodos pueden elevar excepciones de clases hijas de las declaradas en su cabecera mediante la cláusula throws;

  • los métodos redefinidos en una clase

    • pueden eliminar excepciones de la cláusula throws de su cabecera de aquéllas que estaban declaradas en la cabecera del método en su clase padre

    • pueden sustituir excepciones en la cláusula throws de su cabecera por otros excepciones de sus clases hijas;

    • NO pueden añadir nuevas excepciones en la cláusula throws de su cabecera respeto a aquéllas que estaban declaradas en la cabecera del método en su clase padre

clase Base  {

  public void m() throws Exception { ... }

  public void n() throws Exception { ... }
}

class Derivada extends Base  {

  public void m() throws IOException {
    ...
    throw new FileSystemException() ;
    ...
  }

  public void n() {
    ...
  }
}

Clasificación de Excepciones

Ejemplo: dispensers
  • es pocible crear nuevas clases de excepciones siempre que hereden de la clase Throwable o de sus hijas, aunque, por convención, deben heredar de Exception

    • estas clases pueden añadir nuevos atributos y métodos, como en cualquer otra relación de herencia

  • Al meter un elemento en un dispensador acotado que se encuentra lleno, se detecta un error de ejecución, que se puede representar mediante una nueva clase de excepción

Exception

Flujos

  • Los flujos, streams, son objetos que representan secuencias ordenadas de datos que tienen una fuente, flujos de entrada, o un destino, flujos de salida;

    • Las clases de entrada/salida del paquete java.io se definen en términos de flujos, y permiten a los programadores abstraerse de los detalles específicos del sistema operativo al acceder a los recursos del sistema, tales como ficheros, teclado, líneas de comunicaciones, etc.;

  • Tipos de flujos en la biblioteca:

    • de entrada y salida de bytes, cuyas clases abstractas de las que heredan todas las demás son InputStream y OutputStream

    • de entrada y salida de caracteres, cuyas clases abstractas de las que heredan todas las demás son Reader y Writer, donde un caracter Unicode puede estar formado por varios bytes

Flujos de Bytes

FlujoDeBytes
FlujoDeBytes2
class InputStream {
  public abstract int read() throws IOException { ... }
  public int read(byte[] b) throws IOException { ... }
  public int read(byte[] b, int off, int len) throws IOException { ... }
  public long skip(long n) throws IOException { ... }
  public int available() throws IOException { ... }
  public void close() throws IOException { ... }
}
class OutputStream {
  public abstract void write(int b) throws IOException { ... }
  public void write(byte[] b) throws IOException { ... }
  public void write(byte[] b, int off, int len) throws IOException { ... }
  public void flush() throws IOException { ... }
  public void close() throws IOException { ... }
}

Flujos de Caracteres

FlujoDeCaracteres.svg
FlujoDeCaracteres2
class Reader {
  public int read() throws IOException
  public int read(char[] cbuf) throws IOException
  public abstract int read(char[] cbuf, int off, int len) throws IOException
  public long skip(long n) throws IOException
  public boolean ready() throws IOException
  public abstract void close() throws IOException
}
class Writer {
  public void write(int c) throws IOException { ... }
  public void write(char[] cbuf) throws IOException { ... }
  public abstract void write(char[] cbuf, int off, int len) throws IOException { ... }
  public void write(String str) throws IOException { ... }
  public void write(String str, int off, int len) throws IOException { ... }
  public Writer append(char c) throws IOException { ... }
  public Writer append(CharSequence csq) throws IOException { ... }
  public Writer append(CharSequence csq, int start, int end) throws IOException { ... }
  public abstract void flush() throws IOException { ... }
  public abstract void close() throws IOException { ... }
}

Clasificación de Flujos

Flujos de conversión
  • Las clases InputStreamReader permiten convertir bytes en caracteres

    • Los objetos InputStreamReader reciben en su constructor un objeto InputStream que es capaz de leer bytes

public InputStreamReader(InputStream in)
  • Los métodos read de InputStreamReader leen bytes de su InputStream y los convierten en caracteres

  • Las clase OuputStreamWriter permite convertir caracteres en bytes

    • Los objetos OuputStreamWriter reciben en su constructor un objeto OutputStream que es capaz de escribir bytes;

public OuputStreamWriter(OutputStream out)
  • Los métodos write de OutputStreamReader convierten caracteres a bytes y los escriben en su OutputStream;

Flujos de Datos
  • Leer y escribir bytes y caracteres de texto es muy útil, pero a menudo se necesita transmitir datos binarios de los tipos primitivos a través de un flujo

  • Los interfaces DataInput_ y _DataOutput declaran métodos que permiten leer y escribir datos en formato binario

interface DataInput {
  boolean readBoolean();
  char readChar();
  short readShort();
  int readInt();
  long readLong();
  float readFloat();
  double readDouble();
  String readUTF();
}
interface DataInput {
  writeBoolean(boolean);
  writeChar(char);
  writeShort(short);
  writeInt(int);
  writeLong(long);
  writeFloat(float);
  writeDouble(double);
  writeUTF(String);
}
Varios flujos
  • hay varios tipos de flujos que definen comportamientos específicos, tanto en su modalidad de entrada como de salida:

  • los flujos de tipo Filter aplican alguna operación de filtrado cuando leen o escriben datos utilizando otro flujo

    • un objeto FilterReader lee caracteres de otro objeto Reader, procesa los caracteres de alguna manera, y devuelve el resultado

protected FilterReader(Reader in)
  • los flujos de tipo Piped se diseñan en parejas, de forma que las escrituras que realiza un flujo de salida se pueden leer en otro flujo de entrada

public PipedWriter(PipedReader snk) throws IOException
  • los flujos de tipo Buffered añaden almacenamiento intermedio en forma de buffers, de forma que las lecturas y escrituras no requieren acceder al sistema de ficheros en cada invocación.

    • Los flujos de caracteres de este tipo también proporcionan la lectura y escritura de líneas de texto,con retornos de línea

public BufferedReader(Reader in)
public BufferedWriter(Writer out)
  • los llamados flujos en memoria permiten usar estructuras de datos en memoria como fuente o destino de un flujo:

  • los flujos ByteArray usan un vector de byte,

  • los flujos CharArray usan un vector de char,

  • los flujos String usan objetos de la clase String;

  • los flujos de tipo Print proporcionan los métodos print y println que facilitan la escritura de valores de tipos primitivos y objetos en forma de texto legible

    • todos los flujos Print actúan como flujos Filter

    • System.out es un flujo PrintStream

Ficheros

Ejemplo:
  • los flujos File (FileInputStream, FileOutputStream, FileReader y FileWriter) permiten tratar a un fichero como un flujo de entrada o de salida;

    • Para crear un objeto, se usa un constructor que recibe como argumento el nombre del fichero;

FileWriter outTxt = new FileWriter("salida.txt");
FileReader inTxt = new FileReader("entrada.txt");
FileOutputStream outDat = new FileOutputStream("salida.dat");
FileInputStream inDat = new FileInputStream("entrada.dat");
Ficheros de texto
  • Clase plantilla para escribir en un fichero de texto se usa la clase PrintWriter

  • Clase plantilla para leer de un fichero de texto se usa la clase BufferedReader

package es.usantatecla.a0_itinerario.a5_excepciones.a1_writeText;

import java.io.IOException;
import java.io.PrintWriter;

class App {

  public static void main(String[] args) {
    PrintWriter out = null;
    try {
      out = new PrintWriter("./src/main/resources/fichero.txt");
      out.print(1);
      out.print(':');
      out.print(" juan = ");
      out.println(5.5);
      out.println(2 + ": jose = " + 7.2);
      Console.getInstance().writeln("Fichero generado");
    } catch (IOException ex) {
      Console.getInstance().writeln("IOException al escribir:" + ex.getMessage());
    } finally {
      if (out != null) {
        out.close();
      }
    }
  }
}
package es.usantatecla.a0_itinerario.a5_excepciones.a2_readText;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class App {

  public static void main(String[] args) {
    BufferedReader in = null;
    try {
      in = new BufferedReader(new FileReader("./src/main/resources/fichero.txt"));
      String linea;
      while ((linea = in.readLine()) != null) {
        System.out.println(linea);
      }
    } catch (IOException ex) {
      System.out.println("IOException al leer: " + ex.getMessage());
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException ex) {
          System.out.println("IOException al cerrar: " + ex.getMessage());
        }
      }
    }
  }
}
Ficheros binarios
  • Clase plantilla para escribir en un fichero binario se usa la clase DataOutputStream

  • Clase plantilla para leer de un fichero binario se usa la clase DataInputStream

package es.usantatecla.a0_itinerario.a5_excepciones.a3_writeBinary;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

class App {

  public static void main(String[] args) {
    DataOutputStream out = null;
    try {
      out = new DataOutputStream(new FileOutputStream("./src/main/resources/fichero.dat"));
      out.writeInt(1);
      out.writeChar(':');
      out.writeUTF(" juan = ");
      out.writeDouble(5.5);
      Console.getInstance().writeln("Fichero generado");
    } catch (IOException ex) {
      System.out.println("IOException al escribir: " + ex.getMessage());
    } finally {
      if (out != null) {
        try {
          out.close();
        } catch (IOException ex) {
          System.out.println("IOException al cerrar: " + ex.getMessage());
        }
      }
    }
  }
}
package es.usantatecla.a0_itinerario.a5_excepciones.a4_readBinary;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

class App {

  public static void main(String[] args) {
    DataInputStream in = null;
    try {
      in = new DataInputStream(new FileInputStream("./src/main/resources/fichero.dat"));
      System.out.println(in.readInt() + String.valueOf(in.readChar()) +
          in.readUTF() + in.readDouble());
      System.out.println(in.readInt() + String.valueOf(in.readChar()) +
          in.readUTF() + in.readDouble());
    } catch (IOException ex) {
      System.out.println("IOException al leer: " + ex.getMessage());
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException ex) {
          System.out.println("IOException al cerrar: " + ex.getMessage());
        }
      }
    }
  }
}

Serialización de Objetos

Serialización de Objetos
  • resuelve el problema de almacenar en un fichero (o transmitir por una línea de comunicación, etc.) un conjunto de objetos de distintas clases, posiblemente relacionados entre sí, y posteriormente restaurarlos de nuevo en la memoria de un programa, de forma que se mantengan el mismo número de objetos, los mismos valores de sus atributos y las mismas relaciones entre ese conjunto de objetos que en la situación original

    • resolver este problema mediante ficheros de texto o binarios es complejo:

      • porque los objetos tienen un tamaño variable dependiendo de su clase,

      • porque los datos de los objetos deberían almacenarse una sola vez en el fichero,

      • porque no se pueden almacenar y restaurar las referencias, ya que se corresponden con direcciones de memoria, y al volver a cargar un objeto, éste ocupará una dirección de memoria diferente de la original;

Persona
svg
Flujos de Objetos
  • la solución consiste en guardar en el fichero cada objeto con un “número de serie” único;

    • Java proporciona los flujos de bytes ObjectOutputStream y ObjectInputStream para resolver automáticamente el problema de la serialización de objetos;

  • al almacenar un objeto en el fichero:

    • se asocia un número de serie a cada referencia,

    • al encontrar por primera vez una referencia, se almacenan los datos del objeto en el fichero y su número de serie,

    • las siguientes veces que se encuentre esa referencia, escribir sólo el número de serie;

  • al restaurar un objeto del fichero:

    • al restaurar por primera vez un objeto, se crea, se inicializa con sus datos, y se recuerda la asociación entre la nueva referencia y su número de serie,

    • al encontrar sólo su número de serie, recuperar la referencia de ese número de serie;

  • para almacenar (serializar) los objetos se usa la clase ObjectOutputStream, que implementa el interfaz ObjectOutput que, a su vez, extiende el interfaz DataOutput, con lo que, además de poder escribir cualquier dato en formato binario, añade entre otros los siguientes métodos:

  • que permiten serializar objetos en un flujo de bytes;

  • para restaurar (deserializar) los objetos se usa la clase ObjectInputStream, que implementa el interfaz ObjectInput que, a su vez, extiende el interfaz DataInput, con lo que, además de poder leer cualquier dato en formato binario, añade entre otros los siguientes métodos:

  • que permiten deserializar objetos desde un flujo de bytes;

public ObjectOutputStream(OutputStream out) throws IOException
public final void writeObject(Object obj) throws IOException
public void defaultWriteObject() throws IOException
public ObjectInputStream(InputStream in) throws IOException
public final Object readObject() throws IOException, ClassNotFoundException
public void defaultReadObject() throws IOException, ClassNotFoundException
  • el único requisito que se necesita para poder almacenar y restaurar objetos en los flujos de objetos es que las clases de esos objetos deben implementar el interfaz java.io.Serializable:

  • el interfaz Serializable no tiene ningún método, por lo que, en principio, no hay que modificar nada más en las clases de los objetos a serializar;

  • el mecanismo de serialización por defecto de Java se encarga de almacenar y restaurar automáticamente todos los atributos de los objetos, excepto los atributos static; que nunca se serializan ni se deserializan;

class Clase implements Serializable {  }

Programación Parametrizada

Genericos
  • Se desea definir clases cuyos atributos puedan ser de cualquier clase, y para definir métodos que puedan recibir argumentos y devolver resultados de cualquier clase.

    • Una posible solución sería declarando los atributos de estas clases y los argumentos de estos métodos con el tipo más débil posible, por ejemplo, Object.

      • Con esta solución es necesario convertir la dirección devuelta por el método remove(), que es de la clase Object, a una dirección de la clase concreta mediante el operador de conversión de tipos (cast).

      • Al sacar un elemento existe la posibilidad de que se produzca un error de conversión de tipos en tiempo de ejecución al sacar los elementos, que no es detectado en tiempo de compilación, si los objetos que se meten en la pila son de distinta clase de la que se espera que sean al sacarlos.

  • Estos problemas se pueden resolver mediante la declaración de una clase parametrizada, que permita declarar la clase de los elementos de la pila como un parámetro de tipo.

    • A partir de la JDK 1.5 se pueden declarar clases, interfaces y métodos parametrizados, mediante los parámetros de tipo, también llamados variables de tipo.

    • Las clases parametrizadas se denominan clases genéricas; y los métodos parametrizados se denominan métodos genéricos.

    • Tienen las siguientes ventajas:

      • proporcionan una comprobación estricta de tipos en tiempo de compilación;

      • su uso no necesita comprobación de tipos en tiempo de ejecución;

      • producen código más robusto y, en consecuencia, aumentan la facilidad del mantenimiento de los programas.

- Dispensers : fractions - objects
...
9: 1
10: 0
Exception in thread "main" java.lang.ClassCastException: class es.usantatecla.aX_dispensers.a8_parametrized.a1_object.utils.Fraction cannot be cast to class java.lang.Integer (es.usantatecla.aX_dispensers.a8_parametrized.a1_object.utils.Fraction is in unnamed module of loader 'app'; java.lang.Integer is in module java.base of loader 'bootstrap')
        at es.usantatecla.aX_dispensers.a8_parametrized.a1_object.App.main(App.java:49)
  try {
    BoundedQueue boundedQueue = new BoundedQueue(1);
    //boundedQueue.add(2);
    boundedQueue.add(new Fraction(1, 2));
    int element = (int) boundedQueue.remove();
    Console.getInstance().writeln(element);
 } catch (DispenserException e) {
    e.printStackTrace();
  }

Clases Genéricas

Sintaxis Ejemplo
class <ClaseGenerica><<ParametroTipo1>, ...,<ParametroTipo2>> {

  private ParametroTipo1 atributo;

  public ParametroTipo1 metodo(ParametroTipo2 parameter) {
    ...
  }
 ...
}
...
private <ClaseGenerica><<Tipo1/Clasificador1>, ...,<Tipo2/Clasificador2>> objeto
  = new <ClaseGenerica><<Tipo1/Clasificador1>, ...,<Tipo2/Clasificador2>>(...)
  • donde los identificadores encerrados entre < y > son los parámetros de tipo.

    • pueden usarse dentro de la clase parametrizada para declarar el tipo de sus atributos, argumentos de sus métodos, o objetos locales de sus métodos.

    • se especifican posteriormente con un tipo concreto (actual) en la instanciación de un objeto de la clase parametrizada o al declarar una clase hija de la clase parametrizada, lo que produce la encarnación de la clase parametrizada, que se convierte en una clase concreta, proceso que se realiza en tiempo de compilación.

  • Dispensers : objects - generics

  • Map : iterator

  • Con esta solución NO es necesario convertir la dirección devuelta por el método remove() a una dirección de la clase concreta mediante el operador de conversión de tipos (cast)

    • Al sacar un elemento NO existe la posibilidad de que se produzca un error de conversión de tipos en tiempo de ejecución al sacar los elementos, porque el error es detectado en tiempo de compilación, si se trata de meter elementos que no son de la clase adecuada.

  try {
    BoundedQueue<Integer> boundedQueue = new BoundedQueue<Integer>(1);
    boundedQueue.add(2);
    // boundedQueue.add(new Fraction(1, 2)); No compila!!!
    int element = boundedQueue.remove();
    Console.getInstance().writeln(element);
  } catch (DispenserException e) {
    e.printStackTrace();
  }
  • Por razones de compatibilidad con códigos anteriores a la JDK 1.5, está permitido el uso de las clases parametrizadas sin especificar sus parámetros, aunque el compilador genera un aviso

  • estas clases se denominan tipos crudos (raw types):

    • Se puede asignar una referencia de una clase parametrizada a un tipo crudo, y viceversa.

    • Una utilidad de los tipos crudos es poder crear vectores de objetos de clases parametrizadas, lo cual Java no permite en la actualidad;

  BoundedQueue<Double> b0 = new BoundedQueue<Double>(10);
  b0.add(0.0);
  //b0.add(0); // Error!!!
  //b0.add(new Fraction(0,2)); // Error!!!
  Console.getInstance().writeln(""+b0.remove());

  BoundedQueue<Double> b1 = new BoundedQueue(10);
  b1.add(1.1);
  //b1.add(1); // Error!!!
  //b1.add(new Fraction(1,2)); // Error!!!
  Console.getInstance().writeln(""+b1.remove());

  BoundedQueue b2 = new BoundedQueue<Double>(10);
  b2.add(2.2);
  //b2.add(2); // Warning!!! y Error!!!
  //b2.add(new Fraction(2,2)); // Warning!!! y Error!!!
  Console.getInstance().writeln(""+b2.remove());

  BoundedQueue b3 = new BoundedQueue(10); // Integer!!!
  //b3.add(3.3); // Warning!!! y Error!!!
  b3.add(3);
  //b3.add(new Fraction(3,2)); // Warning!!! y Error!!!
  Console.getInstance().writeln(""+b3.remove());

  //BoundedQueue<Integer>[] a0 = new BoundedQueue<Integer>[3]; // Error!!!
  BoundedQueue<Integer>[] a0 = new BoundedQueue[3];
  for(BoundedQueue<Integer> boundedQueue : a0){
    boundedQueue = new BoundedQueue<>(5);
  }

Clases genéricas y herencia

Ejemplo
  • Una clase genérica puede heredar de otra clase genérica

public class BoundedStack<E> extends BoundedDispenser<E>
  • Una clase genérica puede heredar de una clase no genérica

public class BoundedStack<E> implements Serializable
  • Una clase no genérica puede heredar de una clase genérica

public class IntBoundedStack extends BoundedStack<Integer>
public final class Integer extends Number implements Comparable<Integer>

Limitaciones de las clases genéricas

Ejemplo
  • No se pueden encarnar clases genéricas con tipos primitivos

BoundedStack<int> intBoundedStack; // ERROR
  • No se pueden crear clases parametrizadas de excepciones

public class XException<E> extends Exception { ... } // ERROR
  • No pueden aparecer genéricos en las cláusulas catch

try { ... } catch (E e) { ... } // ERROR
  • No se pueden crear vectores de objetos de clases genéricas

public class BoundedStack<E> {

   protected E[] elements;
   ...
   public BoundedStack(int size) {
       this.elements = new E[size]; // ERROR
       this.elements = (E[]) new Object[size]; // AVISO
   ...
   }
}

PilaAcotada<Integer>[] pilas = new PilaAcotada<Integer>[10];        // ERROR
PilaAcotada<Integer>[] pilas = new PilaAcotada[10];                // AVISO

Parámetros Limitados

Sintaxis: Ejemplo
  • En la declaración de un parámetro de tipo de una clase parametrizada se puede especificar una restricción que debe cumplir ese tipo; estos parámetros de tipo se conocen como parámetros de tipo limitados (bounded).

class <clase><<parámetro> extends <tipoBase>,> {
  ...
}
  • donde se especifica que el parámetro de tipo que se declara <parámetro> debe ser el tipo <tipoBase> o cualquier tipo derivado de él;

    • el tipo base puede ser una clase o un interfaz;

    • se pueden especificar más interfaces separándolos por &;

    • el tipo base puede estar, a su vez, parametrizado.

  • por ejemplo, la clase Interval puede parametrizarse, pero con la restricción de que sus elementos sean comparables: bounded

interface Comparable<T> {
   int comparteTo(T o);
}

Parámetros Comodines

  • Código con error de compilación porque la clase List<Double> no es una subclase de List<Number> aunque Double sea una subclase de Number

  List<Double> doubleList = new List<Double>();
  List<Number> numberList = doubleList; // !!!ERROR
  numberList.add(Integer.valueOf(3));
  Double value = doubleList.get(0);

La razón es que si fuera así, entonces las siguientes sentencias, harían que pudiéramos copiar una referencia a un entero en una referencia a un doble, lo cual es incorrecto

  • Los parámetros de tipos comodines (wildcards) son parámetros sin nombre que pueden usarse para declarar tipos parametrizados de los atributos, argumentos, objetos locales y valores devueltos de métodos de cualquier clase, parametrizada o no; y que representan únicamente que se trata de un tipo cualquiera desconocido

  • se representan mediante el símbolo ?

  • al ser anónimos no pueden usarse para referirse a él en el interior de la clase o método donde se declaran;

  • pueden limitarse como cualquier otro parámetro de tipo;

  • su principal utilidad consiste en que relajan el sistema de tipos de Java de forma que resulta más fácil asignar instancias de tipos genéricos.

  • El error de compilación no se produce porque el uso del parámetro comodín relaja el sistema de tipos, de manera que las siguientes sentencias son correctas:

  • Sin embargo, usar el parámetro comodín impone que con la referencia no se puedan usar métodos de la clase parametrizada que pudieran producir una incompatibilidad de tipos

  • pero sí se pueden usar métodos que no puedan producir incompatibilidad de tipos

  List<Double> doubleList = new List<Double>();
  // List<Number> numberList = doubleList; // !!!ERROR
  //numberList.add(Integer.valueOf(3));
  Double value = doubleList.get(0);

  // Se podria omitir extends Number
  List<? extends Number> numberList = doubleList;
  //numberList.add(new Double(3)); // !!!ERROR
  //Number numero = new Double(3);
  //numberList.add(numero); // !!!ERROR
  //Double x1 = numberList.get(0); // !!!ERROR

  Number number = numberList.get(0);
  String string = numberList.toString();
  numberList.clear();
  string = numberList.toString();

Métodos Genéricos

  • Los métodos también se pueden parametrizar, tanto si están en una clase parametrizada como si no lo están.

    • Para parametrizar un método se declaran los parámetros de tipo antes de la declaración del tipo del valor devuelto por el método.

<acceso> <<parámetro1>,,<parámetroN>>
<tipoDevuelto> <nombreMétodo>(<argumentos>) {
 ...
}
  • Los parámetros de tipo pueden usarse dentro del método parametrizado para declarar el tipo del valor devuelto por el método, de sus argumentos y de sus objetos locales.

  • Estos parámetros de tipo (formales) se especifican posteriormente con un tipo concreto (actual) al invocar el método parametrizado, lo que produce la encarnación del método.

  • Ejemplo: greaters

Aplicaciones

Colecciones

Java proporciona en el paquete java.util un conjunto de clases para representar y manejar estructuras de datos.

  • Antes de la aparición de la plataforma Java 2, sólo se disponía de un conjunto muy limitado de clases para las estructuras de datos más comunes: Vector, Stack, Hashtable, y el interfaz Enumeration para recorrer los elementos de estas clases.

  • Java 2 incorpora un framework más completo inspirado en la librería STL de C++, pero manteniendo compatibles las clases heredadas de las versiones anteriores.

  • Esta biblioteca de clases separa los interfaces de sus implementaciones, lo que proporciona mayor abstracción al usar la biblioteca, y facilita la extensibilidad de la misma.

  • A partir de la JDK 1.5 las clases de la biblioteca son clases parametrizadas.

Iterator
Collection
Map
Collection2
Map2
  • Interfaz Collection<E>: Es la raíz de la jerarquía de las clases de colecciones, y proporciona los métodos comunes a todas ellas:

int size()
boolean isEmpty()
boolean contains(Object o)
boolean containsAll(Collection<?> c)
Iterator<E> iterator()
Object[] toArray()
<T> T[] toArray(T[] a)
boolean add(E e)
boolean remove(Object o)
boolean addAll(Collection<? extends E> c)
boolean removeAll(Collection<?> c)
boolean retainAll(Collection<?> c)
void clear()
boolean equals(Object o)
int hashCode()
  • Interfaz Iterator<E>: Permite recorrer los elementos de las clases de colecciones:

    • donde el método remove() debe llamarse sólo después de next(), y elimina de la colección el último elemento devuelto por éste;

    • no debe modificarse una colección mientras un iterador la recorre de ninguna otra manera que invocando remove() sobre ese iterador, porque, en otro caso, el comportamiento del iterador no está definido (la implementación actual produce una excepción ConcurrentModificationException);

boolean hasNext()
E next()
void remove()

Listas

  • Interfaz List<E>: Representa una secuencia de elementos que ocupan una cierta posición en la colección, en la que puede haber elementos repetidos.

E get(int index)
E set(int index, E element)
void add(int index, E element)
E remove(int index)
int indexOf(Object o)
int lastIndexOf(Object o)
ListIterator<E> listIterator()
ListIterator<E> listIterator(int index)
List<E> subList(int fromIndex, int toIndex)
boolean addAll(int index, Collection<? extends E> c)
  • Interfaz ListIterator<E>: Recorre los elementos de una lista:

boolean hasPrevious()
E previous()
int nextIndex()
int previousIndex()
void add(E e)
void set(E e)
  • donde el método remove() debe llamarse sólo después de next() o previous(), y elimina de la colección el último elemento devuelto por éstos;

  • donde add() inserta justo antes del elemento que se obtendría con next() y justo después del elemento que se obtendría con previous();

  • set() reemplaza el último elemento devuelto por next() o previous(), y sólo puede invocarse si después de estas operaciones no se ha invocado add() o set();

    • Las clases que implementan el interfaz List<E> son:

  • Clase ArrayList<E>: que proporciona una implementación basada en vectores de elementos que autoajustan su tamaño según se añaden elementos;

public ArrayList()
public ArrayList(int initialCapacity)
public ArrayList(Collection<? extends E> c)
public void trimToSize()
public void ensureCapacity(int minCapacity)
  • Clase LinkedList<E>: que utiliza listas doblemente enlazadas; además implementa el interfaz Deque<E>, por lo que puede usarse para tratar con colas (se verá más adelante);

public LinkedList()
public LinkedList(Collection<? extends E> c)
  • Clase Vector<E>: también usa vectores autoajustables, y se mantiene por razones de compatibilidad con código heredado; además está sincronizada para evitar accesos concurrentes, lo que conlleva un cierto sobrecoste adicional;

public Vector()
public Vector(int initialCapacity)
public Vector(int initialCapacity, int capacityIncrement)
public Vector(Collection<? extends E> c)
public void copyInto(Object[] anArray)
public void trimToSize()
public void ensureCapacity(int minCapacity)
public void setSize(int newSize)
public int capacity()
public Enumeration<E> elements()
public int indexOf(Object o, int index)
public int lastIndexOf(Object o, int index)
public E elementAt(int index)
public E firstElement()
public E lastElement()
public void setElementAt(E obj, int index)
public void removeElementAt(int index)
public void insertElementAt(E obj, int index)
public void addElement(E obj)
public boolean removeElement(Object obj)
public void removeAllElements()
  • Stack<E>: Representa una pila LIFO.

public Stack()
public E push(E item)
public E pop()
public E peek()
public boolean empty()
public int search(Object o)

Colas

  • Interfaz Queue<E>: Las colas ordenan sus elementos según un orden determinado (normalmente FIFO, aunque no necesariamente):

boolean offer(E e)
E remove()
E poll()
E element()
E peek()
Excepción No excepción

Inserción

add()

offer()

Extracción

remove()

poll()

Consulta

element()

peek()

  • La única clase que implementa el interfaz Queue<E> es:

  • Clase PriorityQueue<E>: proporciona una implementación basada en prioridades que se establecen por el orden natural de sus elementos (según el interfaz Comparable) o por un comparador de elementos que se suministra a la cola en su construcción. Todas las claves deben implementar el interfaz Comparable (o ser aceptadas por su Comparator).

public PriorityQueue()
public PriorityQueue(int initialCapacity)
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator)
public PriorityQueue(Collection<? extends E> c)
public PriorityQueue(PriorityQueue<? extends E> c)
public PriorityQueue(SortedSet<? extends E> c)
  • Interfaz Deque<E>: Son colas que permiten la inserción y extracción de elementos en ambos extremos (double ended queue).

void addFirst(E e)
void addLast(E e)
boolean offerFirst(E e)
boolean offerLast(E e)
E removeFirst()
E removeLast()
E pollFirst()
E pollLast()
E getFirst()
E getLast()
E peekFirst()
E peekLast()
boolean removeFirstOccurrence(Object o)
boolean removeLastOccurrence(Object o)
void push(E e)
E pop()
Iterator<E> descendingIterator()
  • Las clases que implementan el interfaz Deque<E> son:

  • Clase LinkedList<E>: Implementación mediante listas doblemente enlazadas.

public LinkedList()
public LinkedList(Collection<? extends E> c)
  • Clase ArrayDeque<E>: Implementación mediante vectores autoajustables.

public ArrayDeque()
public ArrayDeque(Collection<? extends E> c)

Conjuntos

  • Representa una colección de elementos no repetidos. No añade ningún método nuevo a Collection<E>, sólo estipula ciertas restricciones en sus métodos;

  • Las clases que implementan este interfaz son:

  • Clase EnumSet<E extends Enum<E>>: Los elementos del conjunto deben ser valores de enumerados. Proporcionan una representación muy compacta y eficiente. Los elementos se recorren según su orden natural. La clase es abstracta y sólo tiene métodos genéricos estáticos para crear los conjuntos.

public static <E extends Enum<E>> EnumSet<E>
noneOf(Class<E> elementType)
public static <E extends Enum<E>> EnumSet<E>
allOf(Class<E> elementType)
public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s)
public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)
public static <E extends Enum<E>> EnumSet<E>
    complementOf(EnumSet<E> s)
public static <E extends Enum<E>> EnumSet<E> of(E e)
public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2)
public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3)
public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4)
public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest)
public static <E extends Enum<E>> EnumSet<E> range(E from, E to)
public EnumSet<E> clone()
  • Clase HashSet<E>: Implementación mediante una tabla hash (realmente un HashMap). No garantiza ningún orden al iterar sobre el conjunto.

public HashSet()
public HashSet(int initialCapacity)
public HashSet(int initialCapacity, float loadFactor)
public HashSet(Collection<? extends E> c)
  • Clase LinkedHashSet<E>:# Implementación mediante tabla hash y listas enlazadas (mediante LinkedHashMap), en la que los elementos se recorren en el mismo orden en el que se insertaron.

public LinkedHashSet()
public LinkedHashSet(int initialCapacity)
public LinkedHashSet(int initialCapacity, float loadFactor)
public LinkedHashSet(Collection<? extends E> c)
  • Interfaz SortedSet<E>: Representa un conjunto que establece un orden total sobre sus elementos. Los elementos se ordenan por su orden natural (según el interfaz Comparable) o por un comparador de elementos que se suministra al conjunto en su construcción. Todas las claves deben implementar el interfaz Comparable (o ser aceptadas por su Comparator).

Comparator<? super E> comparator()
SortedSet<E> subSet(E fromElement, E toElement)
SortedSet<E> headSet(E toElement)
SortedSet<E> tailSet(E fromElement)
E first()
E last()
  • Interfaz NavigableSet<E>: Extiende SortedSet<E> para buscar un elemento menor, menor o igual, mayor o igual, y mayor que un cierto elemento dado, más otros métodos de búsqueda.

E lower(E e)
E floor(E e)
E ceiling(E e)
E higher(E e)
E pollFirst()
E pollLast()
NavigableSet<E> descendingSet()
Iterator<E> descendingIterator()
NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive)
NavigableSet<E> headSet(E toElement, boolean inclusive)
NavigableSet<E> tailSet(E fromElement, boolean inclusive)
SortedSet<E> subSet(E fromElement, E toElement)
SortedSet<E> headSet(E toElement)
SortedSet<E> tailSet(E fromElement)
  • La única clase que implementa el interfaz NavigableSet<E> es:

  • Clase TreeSet<E>: Implementación mediante TreeMap, en la que los elementos se recorren según su orden natural.

public TreeSet()
public TreeSet(Comparator<? super E> comparator)
public TreeSet(Collection<? extends E> c)
public TreeSet(SortedSet<E> s)

Mapas

  • Interfaz Map<K,V>: Un mapa representa una colección de elementos formados por una clave y un valor. En un mapa no puede haber elementos con claves repetidas, cada clave puede tener un valor como máximo.

boolean containsKey(Object key)
boolean containsValue(Object value)
V get(Object key)
V put(K key, V value)
V remove(Object key)
void putAll(Map<? extends K,? extends V> m)
Set<K> keySet()
Collection<V> values()
Set<Map.Entry<K,V>> entrySet()
  • Las clases que implementan este interfaz son:

  • Clase EnumMap<K extends Enum<K>,V>: Implementación para usarse con claves de tipo enumerados. Las claves deben ser valores de enumerados. Proporcionan una representación muy compacta y eficiente basada en vectores. Los elementos se recorren según su orden natural.

public EnumMap(Class<K> keyType)
public EnumMap(EnumMap<K,? extends V> m)
public EnumMap(Map<K,? extends V> m)
  • Clase HashMap<K,V>: Implementación mediante una tabla hash. No garantiza ningún orden al iterar sobre el mapa.

public HashMap()
public HashMap(int initialCapacity)
public HashMap(int initialCapacity, float loadFactor)
public HashMap(Map<? extends K,? extends V> m)
  • Clase LinkedHashMap<K,V>: Implementación mediante una tabla hash y listas doblemente enlazadas. Los elementos se recorren en el orden de inserción de sus claves.

public LinkedHashMap()
public LinkedHashMap(int initialCapacity)
public LinkedHashMap(int initialCapacity, float loadFactor)
public LinkedHashMap(Map<? extends K,? extends V> m)
public LinkedHashMap(int initialCapacity, float loadFactor,
     boolean accessOrder)
  • Clase WeakHashMap<K,V>: Implementación mediante una tabla hash y claves débiles. Los elementos cuyas claves dejan de ser referenciadas se destruyen automáticamente.

public WeakHashMap()
public WeakHashMap(int initialCapacity)
public WeakHashMap(int initialCapacity, float loadFactor)
public WeakHashMap(Map<? extends K,? extends V> m)
  • Clase IdentityHashMap<K,V>: Implementación mediante una tabla hash y con comparación de claves y valores mediante == en lugar de equals.

public IdentityHashMap()
public IdentityHashMap(int expectedMaxSize)
public IdentityHashMap(Map<? extends K,? extends V> m)
  • Interfaz SortedMap<K,V>: Un mapa que proporciona un orden total sobre sus claves. El mapa se ordena según el orden natural de sus claves, o mediante un Comparator que se suministra al crear el mapa. Este orden se sigue al iterar sobre las colecciones que devuelve el mapa. Todas las claves deben implementar el interfaz Comparable (o ser aceptadas por su Comparator).

Comparator<? super K> comparator()
SortedMap<K,V> subMap(K fromKey, K toKey)
SortedMap<K,V> headMap(K toKey)
SortedMap<K,V> tailMap(K fromKey)
K firstKey()
K lastKey()
Set<K> keySet()
  • Interfaz NavigableMap<K,V> (I): Extiende SortedMap<E> para buscar un elemento menor, menor o igual, mayor o igual, y mayor que un cierto elemento dado, más otros métodos de búsqueda.

Map.Entry<K,V> lowerEntry(K key)
K lowerKey(K key)
Map.Entry<K,V> floorEntry(K key)
K floorKey(K key)
Map.Entry<K,V> ceilingEntry(K key)
K ceilingKey(K key)
Map.Entry<K,V> higherEntry(K key)
K higherKey(K key)
Map.Entry<K,V> firstEntry()
Map.Entry<K,V> lastEntry()
Map.Entry<K,V> pollFirstEntry()
Map.Entry<K,V> pollLastEntry()
NavigableMap<K,V> descendingMap()
  • Interfaz NavigableMap<K,V> (II):

NavigableSet<K> navigableKeySet()
NavigableSet<K> descendingKeySet()
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                         K toKey, boolean toInclusive)
NavigableMap<K,V> headMap(K toKey, boolean inclusive)
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
  • La única clase que implementa el interfaz NavigableMap<K,V> es:

  • Clase TreeMap<K,V>: Implementación mediante un árbol, en la que los elementos se recorren según su orden natural (o en el orden que proporciona su Comparator).

public TreeMap()
public TreeMap(Comparator<? super K> comparator)
public TreeMap(Map<? extends K,? extends V> m)
public TreeMap(SortedMap<K,? extends V> m)
Aplicaciones
  • MultiMap - v0

Sintesis

Bibliografía

Obra, Autor y Edición Portada Obra, Autor y Edición Portada

Ponente

  • Luis Fernández Muñoz

setillo

  • Doctor en Inteligencia Artificial por la UPM

  • Ingeniero en Informática por la UMA

  • Diplomado en Informática por la UPM

  • Profesor Titular de ETSISI de la UPM