Tipos crudos y código heredado

Avanzado

Debido a que el soporte para genéricos no existía antes de JDK 5, era necesario que Java proporcionara alguna ruta de transición desde el código antiguo, pre-genérico. En pocas palabras, el código heredado pre-genéricos tenía que seguir siendo funcional y compatible con los genéricos. Esto significaba que el código pre-genérico debe poder funcionar con genéricos, y el código genérico debe poder funcionar con código pre-genérico.

Para manejar la transición a los genéricos, Java permite que se use una clase genérica sin ningún tipo de argumentos. Esto crea un tipo crudo (sin procesar) para la clase. Este tipo sin procesar es compatible con el código heredado, que no tiene conocimiento de los genéricos. El principal inconveniente de usar el tipo crudo es que se pierde la seguridad de tipo de los genéricos.

1. Demostración de Tipos crudos (raw type) en Java

Aquí hay un ejemplo que muestra un raw type en acción:

class Gen<T>{
    T ob; //declarar un objeto de tipo T

    // Pase al constructor una referencia
    // a un objeto de tipo T.

    Gen(T o){
        ob=o;
    }

    T getOb(){
        return ob;
    }
}

// Demostración de raw type
class DemoRaw {
    public static void main(String[] args) {
        //Crear un objeto Gen para Integers
        Gen<Integer> iOb= new Gen<Integer>(28);

        //Crear un objeto Gen para Strings
        Gen<String> sOb= new Gen<String>("Prueba");

        // Crear un objeto Gen sin-formato (raw-type)
        // y asígnele un valor Double.
        Gen raw= new Gen(28.5);

        // Cast es necesario porque el tipo es desconocido
        double d= (Double) raw.getOb();
        System.out.println("Valor: "+d);

        // El uso de un tipo sin formato puede generar
        // excepciones en tiempo de ejecución.
        // Aquí hay unos ejemplos.

        // El siguiente cast causa un error de tiempo de ejecución!
        // int i = (Integer) raw.getOb();

        // Esta asignación anula la seguridad de tipo.
        // sOb=raw;
        //  String str= sOb.getOb(); //Error run-time

        //Esta asignación también anula la seguridad de tipo.
        // raw = iOb;
        // d= (Double) raw.getOb(); //Error run-time
    }
}

Este programa contiene varias cosas interesantes. Primero, se crea un tipo sin procesar de la clase Gen genérica mediante la siguiente declaración:

Gen raw = new Gen(28.5);

Observe que no se especifican argumentos de tipo. En esencia, esto crea un objeto Gen cuyo tipo T es reemplazado por Object.

2. Por qué no usar raw type

Un tipo crudo (raw type) no es seguro. Por lo tanto, a una variable de un tipo crudo se le puede asignar una referencia a cualquier tipo de objeto Gen. También se permite lo contrario, en el que a una variable de un tipo de Gen específico se le puede asignar una referencia a un objeto Gen crudo. Sin embargo, ambas operaciones son potencialmente inseguras porque se elude el mecanismo de verificación de tipos de genéricos.

Esta falta de seguridad de tipo se ilustra con las líneas comentadas al final del programa. Examinemos cada caso. Primero, considere la siguiente situación:

int i = (Integer) raw.getOb();

En esta declaración, se obtiene el valor de ob dentro de raw, y este valor se convierte en Integer. El problema es que Raw contiene un valor Double, no un valor Integer. Sin embargo, esto no se puede detectar en tiempo de compilación porque el tipo de raw es desconocido. Por lo tanto, esta instrucción falla en tiempo de ejecución.

La siguiente secuencia asigna a sOb (una referencia de tipo Gen<String>) una referencia a un objeto Gen crudo:

sOb=raw;
String str= sOb.getOb();

La tarea en sí es sintácticamente correcta, pero cuestionable. Como sOb es del tipo Gen<String>, se supone que contiene un String. Sin embargo, después de la asignación, el objeto al que se refiere sOb contiene un Double. Por lo tanto, en el tiempo de ejecución, cuando se intenta asignar los contenidos de sOb a str, se produce un error en tiempo de ejecución porque sOb ahora contiene un Double. Por lo tanto, la asignación de una referencia bruta a una referencia genérica evita el mecanismo de seguridad de tipo.

La siguiente secuencia invierte el caso anterior:

raw = iOb;
d= (Double) raw.getOb()

Aquí, se asigna una referencia genérica a una variable de referencia raw. Aunque esto es sintácticamente correcto, puede provocar problemas, como se ilustra en la segunda línea. En este caso, raw ahora se refiere a un objeto que contiene un objeto Integer, pero el cast asume que contiene un Double. Este error no puede evitarse en tiempo de compilación. Por el contrario, causa un error de tiempo de ejecución.

3. Advertencias no verificadas (unchecked warnings)

Debido a la posibilidad de peligro inherente a los tipos crudos, javac muestra advertencias no verificadas cuando se usa un tipo crudo de una manera que podría poner en peligro la seguridad del tipo. En el programa anterior, estas líneas generan advertencias no verificadas:

Gen raw= new Gen(28.5);
sOb = raw

En la primera línea, es el uso de Gen sin un argumento de tipo que causa la advertencia. Y en la segunda línea, es la asignación de una referencia en bruto a una variable genérica que genera la advertencia.

Al principio, puede pensar que esta línea también debe generar una advertencia no verificada, pero no:

raw = iOb;

No se emite ninguna advertencia del compilador porque la asignación no causa ninguna otra pérdida de seguridad de tipo de la que ya se había producido cuando se creó raw.

Un último punto: debe limitar el uso de tipos crudos a aquellos casos en los que debe mezclar el código heredado con un código genérico moderno. Los tipos crudos son simplemente una característica de transición y no algo que debería usarse para un nuevo código.

Genéricos en Java
  • Tipos Crudos o Raw Type

Sobre el Autor:

Hey hola! Yo soy Alex Walton y tengo el placer de compartir conocimientos hacía ti sobre el tema de Programación en Java, desde cero, Online y Gratis.

Deja una Respuesta

*

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.