Java中标记的含义是什么?

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

 //  occurs 3 times in the entire program. When it is replaced with  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; } 

编辑:当然,当我们使用类似generics类型标记时,它必须出现在类声明中。 这里在类声明中没有也没有 ,但它仍然可以编译并正常运行。

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

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

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

这是在类型参数中使用通配符的示例。 即一般类型。 通配符参数化类型是generics类型的实例化,其中至少一个类型参数是通配符。 通配符参数化类型的示例是CollectionList ListComparator ComparatorPair

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

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

那么两者之间没有太大的区别.. – 采取所有类型的对象

  -is also called `formal type parameter` makes use of what ever type of object you pass in .. for instance you can do this with  and not with  public class Box { 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.pdf和http://download.oracle.com/javase/tutorial/java/generics/gentypes.html

括号中的字母如将是一个类型参数。 你会说class StopAlarmTask意味着你正在使用类型T参数化类型StopAlarmTask 。 类型参数T将成为类型的一部分,类似于构造函数参数成为新实例的一部分。

然后,每当您声明StopAlarmTask ,您将提供一个类型,例如String ,以填充类型参数T 然后,您可以在类主体中引用该类型参数。 例如,您可以定义采用T或返回T ,或使用T参数化成员变量(如fSchedFuture 。 例如,如果您将StopAlarmTask的声明参数化为StopAlarmTask ,那么String将被捕获​​为T并且无论您在该StopAlarmTask使用T ,它都将充当String

但是,在您列出的代码中, StopAlarmTask没有类型参数,无法使用任何类型进行参数化。 在类体中没有捕获的类型称为T

另一方面, 表示“我不知道它将是哪种类型;我甚至不知道它将是某人用来参数化StopAlarmTask的类型。”

你可以参数化StopAlarmTask ,在这种情况下你可以有两个变量:

 private ScheduledFuture fSchedFuture1; private ScheduledFuture fSchedFuture2; 

第一个声明表明ScheduledFuture的类型参数与封闭的StopAlarmTask的类型参数相同。 例如, StopAlarmTask会使fSchedFuture1进入ScheduledFuture 。 第二个声明说我们不知道ScheduledFuture的类型参数是什么,即使我们知道封闭的StopAlarmTask的类型参数。

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

请参阅什么是原始类型,为什么我们不应该使用它? 有关原始类型和generics的良好讨论。

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

 private final class StopAlarmTask implements Runnable { StopAlarmTask(ScheduledFuture aSchedFuture) { fSchedFuture = aSchedFuture; } public void run() { /* */ } private ScheduledFuture fSchedFuture; } 

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

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

编辑:

严格适用于Collections。 用作普通class级的类型或模板

StopAlarmTask不是generics类型。

在下面的示例中,您不会认为Foo是generics类型。

 class Foo { Foo(int i) { } doStuff(List numbers) { } } 

StopAlarmTask构造 StopAlarmTask使用generics参数这一事实不会使通用,只是doStuff()使Foo成为generics。

使用通用方式 “引用”generics类型的声明,即没有特异性。 在StopAlarmTask它恰好是构造函数参数。 它是generics类型的“使用”而不是generics类型的声明,因为它“仅仅”是参数声明。

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

 StopAlarmTask(ScheduledFuture aSchedFuture) { ... } 

适用于作为所有 ScheduledFuture ScheduledFuture 实例的所有对象

以下是generics的进一步背景。

使用或其他任何方式声明generics类型ScheduledFuture 。 具体来说, 不会ScheduledFuture<>的声明中使用,因为约定是使用单个大写字母。

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

 class TGeneric1 { List list = new ArrayList(); 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 { List list = new ArrayList(); TGeneric1(EE value) { this.list.add(value); } EE getHead() { return this.list.get(0); } }