Java中的<! - ? - >标记是什么意思?

时间:2011-08-04 08:42:42

标签: java generics

从www.JavaPractices.com复制的此代码中<?>令牌的含义是什么?当我将它替换为用于泛型类型的更常规的<T>时,它无法编译。 (错误:T无法解析为某种类型。)为什么?

// <?> 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;
}

编辑:当然,当我们使用像<T>这样的泛型类型令牌时,它必须出现在类声明中。这里的类声明中没有<T><?>,但它仍然可以编译并正常运行。

8 个答案:

答案 0 :(得分:6)

无法编译,因为您的类不是通用的(也没有任何方法)。在这个特定的例子中,joker(?)意味着ScheduledFuture可以被任何东西参数化。

有时候,如果你在里面使用另一个泛型类并且你不知道将要使用的确切类型,那么将整个类设为通用是没有意义的。 在此示例中,您有三个选项:

  1. 使StopAlarmTask通用(在这种情况下没有意义)
  2. 在ScheduledFuture中使用具体类型,但它只是一种可能的结果类型,例如String或Integer
  3. 使用通配符(< ? >) - 它允许通过FutureResult(String,Integer,您的自定义类)检索任何内容。您还可以将可能的泛型类型的范围缩小到某些子类,例如ScheduledGeneric< ? extends MyObject >或超类:ScheduledGeneric< ? super MyObject >

答案 1 :(得分:2)

这是在类型参数中使用通配符的示例。即一般类型。 通配符参数化类型是泛型类型的实例,其中至少一个类型参数是通配符。通配符参数化类型的示例包括Collection<?>List<? extends Number>Comparator<? super String>Pair<String,?>

通配符参数化类型表示包含泛型类型的具体实例的类型族。正在使用的通配符类型决定了哪些具体参数化类型属于该族。

答案 2 :(得分:1)

那是Generic Type ...通常我们将String,Object或任何其他对象设置为泛型类型......但是在这里它们使它变得通用。和泛型类型代表它可以store or hold的值。它通常用于Collections ..

两者之间没有多少差异...... - 采取所有类型的对象

              <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;
    }
}

了解更多信息,请参阅http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdfhttp://download.oracle.com/javase/tutorial/java/generics/gentypes.html

答案 3 :(得分:1)

答案 4 :(得分:1)

假设this.executorServiceScheduledExecutorService的子类型(自Java 1.5起可用),scheduleWithFixedDelay()的返回类型为ScheduledFuture<?>。您无法将返回类型从ScheduledFuture<?>更改为ScheduledFuture<T>ScheduledFuture<Integer>或其他任何内容。但是,您可以将其更改为ScheduledFuture,因为<?>是一个通配符泛型类型参数,它近似于原始类型以实现向后兼容。

有关原始类型和泛型的详细讨论,请参阅What is a raw type and why shouldn't we use it?

答案 5 :(得分:0)

它可以使用任何参数,如Object,String,Integer ....等等

现在,当您计划使用泛型时,您必须在天使括号内提供类型。

编辑:

<?>严格适用于收藏集。 <T>用作普通班级的类型或模板

答案 6 :(得分:0)

小丑?可以持有任何类型。如果要对所有方法/成员使用相同的类型,则可以使整个类具有通用性。通过编写StopAlarmTask<T>,您可以在整个班级中定义类型T

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

    public void run() 
    { /* */ }

    private ScheduledFuture<T> fSchedFuture;
}

答案 7 :(得分:0)

StopAlarmTask不是通用类型。

在以下示例中,您不认为Foo是泛型类型。

class Foo
{
    Foo(int i)
    { }

    doStuff(List<Integer> numbers)
    { }
}

StopAlarmTask构造函数使用泛型参数的事实不会使泛型超过doStuff()使{{1通用。

使用Foo以通用方式“引用”泛型的声明,即没有特异性。在<?>中它恰好是构造函数参数。它是泛型类型的“使用”,而不是泛型类型的声明,因为它“仅仅”是一个参数声明。

换句话说,简短的回答是方法中的参数

StopAlarmTask

适用于所有T的 StopAlarmTask(ScheduledFuture<?> aSchedFuture) { ... } 实例的所有对象。

以下是关于泛型的进一步背景。

使用ScheduledFuture<T><T>或其他任何内容来声明通用类型<E>。具体来说,ScheduledFuture<T>会在<?>的声明中使用而不是,因为约定是使用单个大写字母。

请注意,以下测试代码,如果提供给编译器,将显示第一个类编译但第二个不编译,所以说有一个使用字母的约定实际上是轻描淡写。

ScheduledFuture<>

以下测试代码中说明,没有单字母约束,因此以下内容也是正确的。

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);
    }
}