[Notas de lectura] Java núcleo la tecnología de volumen # 6.Chapter8

8 programación genérica

8.1 ¿Por qué usar la programación genérica

  • parámetro de tipo (del tipo de los Eparámetros) ( T,, S...)
  • tipo Comodín (comodín del tipo) ?()

Tenga en cuenta el uso tanto de utilidad y diferente.

8.2 Definir clase genérica sencilla

public class Pair<T> {
    private T first;
    private T second;

    public Pair() { first = null; second = null; }
    public Pair(T first, T second) { this.first = first; this.second = second; }

    public T getFirst() { return first; }
    public T getSecond() { return second; }

    public void setFirst(T newValue) { first = newValue; }
    public void setSecond(T newValue) { second = newValue; }
}

8,3 método genérico

Escriba modificador de la variable en la parte posterior, volver al tipo anterior.
métodos genéricos se pueden definir en la categoría general, también se puede definir en clases genéricas.
Cuando se llama a un método genérico, en un tipo específico de paréntesis angulares frente al nombre del método.

8.4 Definición de tipos de variables

Al establecer la variable T se define tipo (unida):

public static <T extends Comparable> T min(T[] a) {. . .}
  • La palabra clave es extends, clase T y tipo pueden ser definidas, o pueden ser una interfaz.
  • Un tipo variable o comodines pueden definir una pluralidad de, por ejemplo: T extends Comparable & Serializable; tipo definido por '&' separada por comas para separar el tipo de variable.
  • La definición de la mayoría de clase uno, y se debe definir en primer lugar en la lista.

8.5 código genérico y máquina virtual

máquina virtual hace objetos de tipo genérico - todos los objetos pertenecen a la categoría general.

8.5.1 Tipo de borrado

Siempre que defina un tipo genérico, proporciona automáticamente un tipo original correspondiente (tipo de prima). Eliminación del tipo original del nombre de tipo genérico es el nombre del parámetro de tipo. Erase (borrada) variable de tipo, y el tipo definido reemplazado.

El primer tipo de original reemplazado con un tipo de variable definido, si no se sustituye por la definición del objeto dado. Para mejorar la eficiencia, si la interfaz de marcador (es decir, la interfaz sin métodos) al final de la lista de límite.

public class Pair {
    private Object first;
    private Object second;

    public Pair() { first = null; second = null; }
    public Pair(Object first, Object second) { this.first = first; this.second = second; }

    public Object getFirst() { return first; }
    public Object getSecond() { return second; }

    public void setFirst(Object newValue) { first = newValue; }
    public void setSecond(Object newValue) { second = newValue; }
}

8.5.2 La traducción expresión genérica

Cuando un programa llama a un método genérico, si el borrado tipo de retorno, los insertos del compilador fundido.

8.5.3 método genérico Traducción

Si el tipo de borrado polimórfico se enfrentaron, por ejemplo:

public class Datelnterval extends Pair<LocalDate> {
    @Override
    public void setSecond(LocalDate second) {
        if (second.compareTo(getFirst()) >= 0)
            super.setSecond(second);
    }
    ...
}

Después de tipo de borrado, se convierten en:

class DateInterval extends Pair {
    public void setSecond(LocalDate second) { . . . }
    . . .
}

Pero después de que el método de borrado es de tipo Par

public void setSecond(Object second);

Cuando los parámetros del método de revestimiento es incompatible con este polimorfismo tenido un conflicto. Por lo tanto, el compilador genera es Datelnterval 桥方法(Método puente,):

public void setSecond(Object second) { setSecond((LocalDate) second); }

Si el método de generación de puente método get, por lo que en la clase Datelnterval, hay dos métodos getSecond:

LocalDate getSecond() // defined in DateInterval 中定义的
Object getSecond() // 桥方法,覆盖 Pair 中的方法,调用第一个方法

Método de firma (el valor de retorno no incluye) los mismos dos métodos no son legales.
Sin embargo, en una máquina virtual, el tipo de parámetro y el retorno tipo procedimiento de determinación. Por lo tanto, el compilador puede generar un rendimiento de sólo dos diferentes tipos de métodos de bytes de código, la máquina virtual para manejar la situación correctamente.

El quinto capítulo se menciona tipos de retorno covariantes también utilizan el método del puente

En resumen, para recordar hechos acerca de la conversión de los genéricos de Java:

  • máquina virtual sin genéricos, sólo las clases y los métodos ordinarios.
  • Todos los tipos de parámetros se definen por su tipo de reemplazo.
  • métodos de puente se sintetizan para mantener el polimorfismo.
  • Con el fin de mantener el tipo de seguridad, si es necesario, insertar fundido.

8.5.4 código heredado de llamadas (abreviado)

8.6 Restricciones y limitaciones

8.6.1 tipo de base no se puede utilizar para parámetro de tipo instantiate

No Pair<double>, solamente Pair<Double>. Porque después del tipo de borrado, Pair sería objeto de dominio, y el objeto no puede ser almacenado doble.

8.6.2 consultas de tipo en tiempo de ejecución sólo se aplica al tipo original

Tales como:

if (a instanceof Pair<String>) // Error
if (a instanceof Pair<T>) // Error
Pair<String> p = (Pair<String>) a; // Warning--can only test that a is a Pair

De hecho, sólo comprueba si a es un par. Cuando se le recordó de los riesgos, tratar de comprobar si un objeto pertenece a un tipo genérico, si se utiliza instanceof obtendrá un error de compilación, si el yeso obtendrá una advertencia. Del mismo modo, el getClassmétodo siempre devuelve el tipo original. Debido a que el objeto total de la máquina virtual tiene una tipos específicos no genéricos.

8.6.3 No se puede crear matrices de tipos parametrizados

Tales como:

Pair<String>[] table = new Pair<String>[10]; // Error
Object[] objarray = table;
objarray[0] = "Hello"; // Error--component type is Pair
objarray[0] = new Pair<Employee>(); // 可以通过数组存储检査

Por lo tanto no se les permite crear (nuevo) tipo parametrizado de matriz. Sin embargo, la declaración es legítima y se puede inicializar utilizando la conversión de tipos.

Pair<String>[] table = (Pair<String>[]) new Pair<?>[10];

Por supuesto que es seguro. Sólo un método seguro y eficaz: ArrayList<Pair<String>>.

8.6.4 advertencia Varargs

número variable Método de parámetros:

public static <T> void addAll(Collection<T> coll, T... ts)
{
    for (t : ts) coll.add(t);
}
// 如下调用:
Collection<Pair<String>> table = . . .;
Pair<String> pair1 = . . .;
Pair<String> pair2 = . . .;
addAll(table, pair1, pair2);

Para llamar a este método, la oportunidad de crear un grupo virtual Pair<String>matriz. Pero esta vez no harán más que una advertencia en lugar de un error. Eliminar esta advertencia puede ser anotada @SuppressWarnings("unchecked")o @SafeVarargs.

8.6.5 Ejemplos de tipos no se convierte oponen

No se puede utilizar new T(...)o T.classtales expresiones.

¿Quieres crear una instancia de la persona que llama puede proporcionar una expresión constructor o dar clase (entonces el método Class.newlnstance).

// 1.构造器表达式
Pair<String> p = Pair.makePair(String::new);
public static <T> Pair<T> makePair(Supplier<T> constr)
{
    return new Pair<>(constr.get(), constr.get());
}
// 2. 提供class
Pair<String> p = Pair.makePair(String.class);
public static <T> Pair<T> makePair(Class<T> cl)
{
    try { return new Pair<>(cl.newInstance(), cl.newInstance()); }
    catch (Exception ex) { return null; }
}

8.6.6 no puede construirse matriz genérica

No se puede new T[...].

  • Expresiones o una configuración reflectante, ver P324
  • ArrayList.toArrayEjemplos, ver P324

8.6.7 contexto estático variable de tipo genérico de clase no válida

No puede hacer referencia dominio variable de tipo o en un método estático.

public class Singleton<T> {
    private static T singleInstance; // Error
    public static T getSingleInstance() // Error
    {
        if (singleInstance == null) construct new instance of T
        return singleInstance;
    }
}

Declaración Singleton<Random>y Singleton<JFileChooser>, pero sólo después de borrado tipo de clase Singleton, que tiene sólo un dominio SingleInstance.

8.6.8 No se puede tirar o clase genérica instancia de captura

Ni tiren ni capturar un objeto de la clase genérica. De hecho, incluso la clase genérica se extiende Throwable es ilegal.

public class Problem<T> extends Exception { /* . . . */ } // Error--can't extend Throwable

cláusula catch no puede utilizar la variable de tipo:

public static <T extends Throwable> void doWork(Class<T> t) {
    try {
        do work
    }
    catch (T e) { // Error--can't catch type variable
        Logger.global.info(...)
    }
}

Sin embargo, se permite el uso de variables excepción de especificación de tipo.

public static <T extends Throwable> void doWork(T t) throws T { // OK
    try {
        do work
    }
    catch (Throwable realCause) {
        t.initCause(realCause);
        throw t;
    }
}

8.6.9 puede eliminar la inspección de excepción comprobada de

8.6.10 atención a borrarse después de un conflicto

8.7 tipos genéricos de las reglas de herencia

  • Si S tienen ningún contacto con la T, por lo general, Pair<S>con Pair<T>ninguna conexión.

  • Siempre se puede convertir un tipo parametrizado es un tipo primitivo. Pero hay riesgos, tales como:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair rawBuddies = managerBuddies; // OK
rawBuddies.setFirst(new File(". . .")); // only a compile-time warning
Manager one = rawBuddies.getFirst();    // 抛出 ClassCastException 异常 
  • clase genérica se puede extender o aplicar otras clases genéricas. , No hay diferencia entre las clases ordinarias al respecto.
    Por ejemplo, ArrayList<T>clase implementa List<T>la interfaz. Esto significa que una ArrayList<Manager>se pueden convertir en uno List<Manager>. Sin embargo, como se ha visto antes, un ArrayList<Manager>no es un ArrayList<Employee>o List<Employee>.

8.8 Tipo de comodín

8.8.1 concepto Comodín

Tipo de carácter comodín, lo que permite el parámetro de tipo de cambio. Por ejemplo:

Pair<? extends Employee>

Es el tipo de parámetro es cualquier subclase de Empleado Par tipo genérico.

Pair<Employee>Y Pair<Manager>todos los Pair<? extends Employee>subtipos.

El uso de comodines por Pair<? extends Employee>referencia no dañará Pair<Manager>:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair<? extends Employee> wildcardBuddies = managerBuddies; // OK
wildcardBuddies.setFirst(lowlyEmployee); // compile-time error

Debido a que Pair<? extends Employee>el método es el siguiente:

? extends Employee getFirst()
void setFirst(? extends Employee)

Esto no será posible llamar al método setFirst. Las necesidades del compilador para conocer sólo un subtipo del empleado, pero no sabe
específicamente qué tipo. Se transmite a ningún tipo particular de las basuras. Después de todo, ?no se puede utilizar para la coincidencia.
consumo problemático de GetFirst no existe: el valor del retorno GetFirst es asignado a una referencia Empleado perfectamente legal.

Aquí es donde no se limita comodín punto clave: ahora hay una manera de distinguir entre un seguro 访问器método y peligroso 更改器camino a seguir.

8.8.2 comodín supertipo definir

通配符限定Y 类型变量限定es muy similar, pero también puede especificar un tipo de súper limitado (supertipo ligada).

Por ejemplo, Pair<? super Manager>hay métodos:

void setFirst(? super Manager)
? super Manager getFirst()

El compilador no puede saber método del tipo específico setFirst, y por lo tanto no puede aceptar el argumento de tipo Empleado o de objetos cuando se llama a este método. Objeto Manager sólo puede pasar tipo, o una sub-tipo del objeto.
Además, si se llama a GetFirst, no podemos garantizar el tipo de retorno del objeto, sólo se puede asignar a un objeto.

Intuitivamente, comodines con supertipo pueden ser escritos para definir un objeto genérico con el subtipo comodín definido se puede leer desde el objeto genérico.

8.8.3 comodín indefinida

Tal Pair<?>como: .

? getFirst()
void setFirst(?)

GetFirst valor de retorno sólo se puede asignar a un objeto. método setFirst no puede ser llamado, incluso pasando objeto Object (se le puede llamar setFirst(null)). Sin embargo, se puede hacer pasar en el tipo original método Par setFirst de cualquier objeto Object.

  • Utilizar operaciones simples que la legibilidad más fuertes. La detección de un par contiene una referencia nula:
public static boolean hasNulls(Pair<?> p)
{
    return p.getFirst() == null || p.getSecond() == null;
}

8.8.4 captura de Comodín

public static void swap(Pair<?> p) { 
    swapHelper(p);
}

public static <T> void swapHelper(Pair<T> p) {
    T t = p.getFirst();
    p.setFirst(p.getSecond());
    p.setSecond(t);
}

Nota: swapHelper es un método genérico, intercambiar en lugar de tener un fijo Pair<?>parámetro de tipo.
En este caso, la captura swapHelper Comodín parámetro del método T. No se sabe qué tipo es la representación de comodín, pero se trata de un tipo determinado.

8.9 reflexión y genéricos

clase clase es genérico. Por ejemplo, String.classde hecho, una Class<String>clase de objeto (de hecho, es el único objeto).

clases borradas aún conservaban algo de información genérica sobre su origen:
public static Comparable min(Comparable[] a)
se borra por un método genérico:
public static <T extends Comparable<? super T>> T min(T[] a)
Puede utilizar la API de reflexión para determinar:

  • El método genérico tiene un parámetro de tipo de llamada T.
  • Este parámetro tiene un subtipo del tipo definido, que es en sí mismo un tipo genérico. //Comparable<? super T>
  • Esto define el tipo de parámetro tiene un comodín. //? super T
  • Este parámetro tiene un supertipo definir comodín.
  • El método genérico tiene un parámetro de matriz genérica. //T[] a

En otras palabras, se puede reconstruir toda la información sobre las clases y métodos genéricos, como se dan cuenta de que esas declaraciones. Pero usted no sabe el objeto específico o llamada al método es cómo tratar con el tipo de parámetro.

Para expresar la declaración de tipo genérico, utilizando java.lang.reflectla interfaz proporcionada en el paquete Type. Esta interfaz contiene los siguientes subtipos:

  • ClassClass, un tipo específico.
  • Type VariableInterface describe variable de tipo (por ejemplo, T extends Comparable<? super T>).
  • WildcardTypeInterface describe comodines (por ejemplo, ?super T).
  • ParameterizedTypeInterfaces, descripción genérica de una clase o tipo de interfaz (por ejemplo, Comparable<? super T>).
  • GenericArrayTypeInterfaces, Descripción array genérico (por ejemplo, T[]).

Dicha sección para ver la verdad detrás de la tarjeta salvaje y niebla. . . . .

Supongo que te gusta

Origin www.cnblogs.com/caophoenix/p/12557006.html
Recomendado
Clasificación