2011-08-04 42 views
7

从www.JavaPractices.com复制的代码中<?>令牌的含义是什么?当我用通用类型的更传统的<T>替换它时,它不能编译。 (错误:T无法解析为类型。)为什么?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; 
} 

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

+0

看看我的编辑答案.. – ngesh

+0

检查新的编辑 – BOSS

回答

6

它编译失败的,因为你的班级不是通用的(也不是你的任何方法)。在这个特殊的例子中,小丑(?)意味着ScheduledFuture可以被任何参数化。

有时候,如果你在里面使用另一个泛型类,并且你不知道将要使用的确切类型,那么就没有意义使整个类变为泛型。 在这个例子中,你有三个选择:

  1. 使StopAlarmTask通用(有在这种情况下没有意义)在ScheduledFuture
  2. 使用具体类型,但那就只有一个可能的结果类型,例如字符串或整数
  3. 使用通配符() - 它允许检索FutureResult(String,Integer,您的自定义类)的结果。还可以缩小的可能的通用类型的范围到一些亚类,例如ScheduledGeneric< ? extends MyObject >或成超类:ScheduledGeneric< ? super MyObject >
+0

您的答案似乎与用于泛型类型的一致。但是,问题是关于。 – H2ONaCl

+0

请看看我的编辑。希望现在清楚。 –

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

+0

你的回答不介绍之间的差异。 – H2ONaCl

+0

“没有太大的差异”不是一个答案,LOL。 – H2ONaCl

2

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

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

0

它可以像任何参数对象,字符串,整数....等等

现在,当你打算使用泛型,那么你必须提供天使括号内的类型。

编辑:

<?>严格appliable到集合。 <T>用作普通类的类型或模板

+0

您正在描述,但问题是关于。 – H2ONaCl

0

百搭?可以容纳任何类型。如果你想为所有的方法/成员使用相同的类型,你可以使整个类变得通用。通过编写StopAlarmTask<T>,您可以在整个班级中定义类型T

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

    public void run() 
    { /* */ } 

    private ScheduledFuture<T> fSchedFuture; 
} 
+0

您正在描述,但问题是关于。 – H2ONaCl

1

括号内的字母如<T>将是一个类型参数。你会说class StopAlarmTask<T>意味着你正在参数化类型StopAlarmTask与类型T。类型参数T将成为类型的一部分,有点像构造函数参数成为新实例的一部分。

然后,每当您声明StopAlarmTask时,您都会提供一个类型,例如, String,填写类型参数T。然后您可以在类体内引用该类型参数。例如,您可以定义采用T或返回T的方法,或参数化fSchedFutureT等成员变量。例如,如果您将StopAlarmTask<T>的声明参数化为StopAlarmTask<String>,那么String将被捕获为T,并且无论您在该StopAlarmTask内使用T,它都将作为String

但是,在您列出的代码中,StopAlarmTask没有类型参数,不能用任何类型参数化。在课堂内部没有被捕获的类型被称为T

另一方面,<?>的意思是“我不知道它是哪一种类型;我甚至不知道这将是某人用来参数化StopAlarmTask的类型。”

你可以有参数StopAlarmTask<T>,而在这种情况下,你可以有两个变量:

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

第一个声明说,ScheduledFuture的类型参数是一样的封闭StopAlarmTask的类型参数。例如。 StopAlarmTask<String>将使fSchedFuture1成为ScheduledFuture<String>。第二个声明表示我们不知道ScheduledFuture的类型参数是什么,即使我们知道包含StopAlarmTask的类型参数。

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?关于原始类型和泛型的良好讨论。

0

StopAlarmTask不是通用类型。

在以下示例中,您不会认为Foo是一种通用类型。

class Foo 
{ 
    Foo(int i) 
    { } 

    doStuff(List<Integer> numbers) 
    { } 
} 

构造的StopAlarmTask使用泛型参数不会使事实通用比任何doStuff()更使得Foo通用。

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

换言之,简单的答案是,在该方法

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

参数适用于是的ScheduledFuture<T>实例为所有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); 
    } 
} 

在下面的测试代码中说明,没有单字母约束,所以下面也是正确的。

class TGeneric1<EE> { 
    List<EE> list = new ArrayList<EE>(); 
    TGeneric1(EE value) { 
     this.list.add(value); 
    } 
    EE getHead() { 
     return this.list.get(0); 
    } 
} 
相关问题