2011-08-04 20 views
7

¿Cuál es el significado del token <?> en este código copiado de www.JavaPractices.com? Cuando lo reemplazo con el aspecto más convencional <T> utilizado para los tipos genéricos, no se puede compilar. (Error: T no puede resolverse en un tipo). ¿Por qué?¿Cuál es el significado del token <?> en Java?

// <?> occurs 3 times in the entire program. When it is replaced with <T> the 
// program no longer compiles. 

void activateAlarmThenStop() 
{ 
    Runnable myPeriodicTask = new PeriodicTask(); 
    ScheduledFuture<?> soundAlarmFuture = 
     this.executorService.scheduleWithFixedDelay(myPeriodicTask, 
              startT, 
              period, 
              TimeUnit.SECONDS 
             ); 
    Runnable stopAlarm = new StopAlarmTask(soundAlarmFuture); 
    this.executorService.schedule(stopAlarm, stopT, TimeUnit.SECONDS); 
} 

private final class StopAlarmTask implements Runnable 
{ 
    StopAlarmTask(ScheduledFuture<?> aSchedFuture) 
    { 
     fSchedFuture = aSchedFuture; 
    } 

    public void run() 
    { 
     CConsole.pw.println("Stopping alarm."); 
     fSchedFuture.cancel(doNotInterruptIfRunningFlag); 

     executorService.shutdown(); 
    } 
    private ScheduledFuture<?> fSchedFuture; 
} 

Editar: Por supuesto, cuando utilizamos fichas de tipo genérico como <T>, tiene que aparecer en la declaración de clase. Aquí no hay <T> ni <?> en la declaración de la clase, pero aún se compila y se ejecuta correctamente.

+0

vistazo a mi respuesta editado .. – ngesh

+0

comprobar la nueva edición – BOSS

Respuesta

6

Se falla al compilar, porque tu clase no es genérica (ni ninguno de tus métodos). En este ejemplo particular joker (?) Significa que ScheduledFuture puede ser parametrizado por cualquier cosa.

A veces, no tiene sentido hacer toda la clase genérica si utiliza otra clase genérica dentro y no sabe el tipo exacto que se utilizará. En este ejemplo, tenían tres opciones:

  1. hacen StopAlarmTask genérica (no tiene sentido en este caso)
  2. utilización tipo inmediato en ScheduledFuture, pero entonces sería sólo un tipo posible resultado, por ejemplo cuerdas o Entero
  3. comodín de uso() - permite recuperar cualquier cosa como resultado de FutureResult (Cadena, Entero, su clase personalizada). También puede limitar el alcance de un posible tipo genérico en algunas subclases, por ejemplo ScheduledGeneric< ? extends MyObject > o en superclases: ScheduledGeneric< ? super MyObject >
+0

Su respuesta parece consistente con como se usa para los tipos genéricos. Sin embargo, la pregunta es sobre . – H2ONaCl

+0

Por favor, eche un vistazo a mis ediciones. Espero que esté claro ahora. –

1

Eso es Generic Type ... generalmente establecemos String, Object o cualquier otro objeto como tipos genéricos ... pero aquí lo hacen general. y el tipo genérico representa el valor que puede store or hold. su utilizan generalmente en Collections ..

así no hay mucho diff entre los dos .. - toma todo tipo de objetos

   <T>-is also called `formal type parameter` makes use of what ever type of object you pass in .. for instance you can do this with <T> and not with <?> 

public class Box<T> { 

    private T t; // T stands for "Type" 

    public void add(T t) { 
     this.t = t; 
    } 

    public T get() { 
     return t; 
    } 
} 

para más ver http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf y http://download.oracle.com/javase/tutorial/java/generics/gentypes.html

+0

Su respuesta no describe la diferencia entre y . – H2ONaCl

+0

"No hay mucha diferencia" no es una gran respuesta, LOL. – H2ONaCl

2

Este es un ejemplo del uso de comodines en un argumento de tipo. es decir, un tipo genérico. Un tipo parametrizado de comodín es una creación de instancias de un tipo genérico donde al menos un argumento de tipo es un comodín. Los ejemplos de tipos con parámetros comodín son Collection<?>, List<? extends Number>, Comparator<? super String> y Pair<String,?>.

Un tipo parametrizado comodín denota una familia de tipos que comprende instancias concretas de un tipo genérico. El tipo de comodín que se utiliza determina qué tipos de parámetros concretos pertenecen a la familia.

0

Puede tomar cualquier parámetro como objeto, cadena, entero .... y así sucesivamente

Ahora, cuando tiene previsto utilizar los genéricos entonces usted tiene que proporcionar el tipo dentro del soporte ángel.

EDIT:

<?> es estrictamente appliable a Colecciones. <T> utilizado como tipo o plantilla para su clase normal de

+0

Usted está describiendo pero la pregunta es sobre . – H2ONaCl

0

El comodín ? puede contener cualquier tipo. Si desea utilizar el mismo tipo para todos los métodos/miembros, puede hacer que toda la clase sea genérica. Al escribir StopAlarmTask<T>, define el tipo T en toda la clase.

private final class StopAlarmTask<T> implements Runnable 
{ 
    StopAlarmTask(ScheduledFuture<T> aSchedFuture) 
    { 
     fSchedFuture = aSchedFuture; 
    } 

    public void run() 
    { /* */ } 

    private ScheduledFuture<T> fSchedFuture; 
} 
+0

Usted está describiendo pero la pregunta es sobre . – H2ONaCl

1

Una carta en soportes como <T> sería un parámetro de tipo. Diría class StopAlarmTask<T> para indicar que está parametrizando el tipo StopAlarmTask con el tipo T. El parámetro de tipo T se convertiría en una parte del tipo, más o menos como un argumento constructor se convierte en parte de una nueva instancia.

Luego, siempre que declare StopAlarmTask, debe proporcionar un tipo, p. Ej. String, para completar el parámetro de tipo T. Luego puede referirse a ese parámetro de tipo dentro del cuerpo de la clase. Por ejemplo, puede definir métodos que toman un T o devolver un T, o parametrizar variables de miembro como fSchedFuture con T. Por ejemplo, si parametrizó una declaración de StopAlarmTask<T> como StopAlarmTask<String>, entonces String sería capturado como T y dondequiera que use T dentro de ese StopAlarmTask actuaría como String.

Sin embargo, en el código que ha enumerado, StopAlarmTask no tiene un parámetro de tipo y no se puede parametrizar con ningún tipo. No hay ningún tipo capturado para referirse como T dentro del cuerpo de la clase.

Por otro lado, <?> significa "No sé qué tipo será, ni siquiera sé que será del tipo que alguien haya usado para parametrizar StopAlarmTask".

Usted podría tener parametrizado StopAlarmTask<T>, y en ese caso puede tener dos variables:

private ScheduledFuture<T> fSchedFuture1; 
private ScheduledFuture<?> fSchedFuture2; 

La primera declaración dice que el parámetro de tipo de la ScheduledFuture es el mismo que el parámetro de tipo de la StopAlarmTask que encierra. P.ej. StopAlarmTask<String> haría fSchedFuture1 en un ScheduledFuture<String>. La segunda declaración dice que no sabemos cuál es el parámetro de tipo ScheduledFuture, incluso si conocemos el parámetro de tipo del StopAlarmTask adjunto.

1

Suponiendo que this.executorService es un subtipo de ScheduledExecutorService (disponible desde Java 1.5), el tipo de devolución de scheduleWithFixedDelay() es ScheduledFuture<?>. No puede cambiar el tipo de devolución de ScheduledFuture<?> a ScheduledFuture<T>, ScheduledFuture<Integer> ni nada por el estilo. Sin embargo, podría cambiarlo a solo ScheduledFuture ya que <?> es un parámetro de tipo genérico comodín que se aproxima a un tipo sin procesar para compatibilidad con versiones anteriores.

Consulte What is a raw type and why shouldn't we use it? para una buena discusión sobre los tipos crudos y los genéricos.

0

StopAlarmTask no es un tipo genérico.

En el siguiente ejemplo, no creo que Foo sea un tipo genérico.

class Foo 
{ 
    Foo(int i) 
    { } 

    doStuff(List<Integer> numbers) 
    { } 
} 

El hecho de que el constructor de StopAlarmTask utiliza un parámetro genérico no hace que el clase genérica más que doStuff() hace Foo genérico.

Utilice <?> para "hacer referencia a" la declaración de un tipo genérico de forma genérica, es decir, sin especificidad. En StopAlarmTask, resulta ser un parámetro de constructor. Es un "empleo de" un tipo genérico y no una declaración de un tipo genérico porque es "meramente" una declaración de parámetro.

En otras palabras, la respuesta corta es que el parámetro en el método

StopAlarmTask(ScheduledFuture<?> aSchedFuture) 
{ ... } 

es aplicable para todos los objetos que son instancias deScheduledFuture<T> para todos T.

La siguiente es más antecedentes en genéricos.

Utilice <T> o <E> o lo que sea para declarar el tipo genérico ScheduledFuture<T>. Específicamente, <?> sería no se utilizará en la declaración de ScheduledFuture<> porque la convención es usar una sola letra mayúscula.

Tenga en cuenta que el siguiente código de prueba, si se alimenta a un compilador, mostrará que la primera clase compila pero la segunda no, por lo que decir que hay una convención para usar una carta sería insuficiente.

class TGeneric1<E> { 
    List<E> list = new ArrayList<E>(); 
    TGeneric1(E value) { 
     this.list.add(value); 
    } 
    E getHead() { 
     return this.list.get(0); 
    } 
} 

class TGeneric2<?> { 
    List<?> list = new ArrayList<?>(); 
    TGeneric2(? value) { 
     this.list.add(value); 
    } 
    ? getHead() { 
     return this.list.get(0); 
    } 
} 

Ilustrado en el siguiente código de prueba, no hay una sola restricción de letra, por lo que la siguiente también es correcta.

class TGeneric1<EE> { 
    List<EE> list = new ArrayList<EE>(); 
    TGeneric1(EE value) { 
     this.list.add(value); 
    } 
    EE getHead() { 
     return this.list.get(0); 
    } 
} 
Cuestiones relacionadas