1.匿名内部类
泛型还可以应用于内部类以及匿名内部类。下面的例子使用匿名内部类实现了Generator接口:
public class Customer {
private static long counter = 1;
private final long id = counter ++;
private Customer (){
}
public String toString(){
return "Customer" + id;
}
public static Generator<Customer> generator(){
return new Generator<Customer>() {
@Override
public Customer next() {
return new Customer();
}
};
}
}
public class Teller {
private static long counter = 1;
private final long id = counter++;
private Teller(){}
@Override
public String toString() {
return "Teller" + id;
}
public static Generator<Teller> generator = new Generator<Teller>() {
@Override
public Teller next() {
return new Teller();
}
};
}
public class BankTeller {
public static void serve(Teller t,Customer c){
System.out.println(t + "serve" + c);
}
public static void main(String[] args) {
Random random = new Random(47);
Queue<Customer> line = new LinkedList<Customer>();
Generators.fill(line, Customer.generator(), 15);
List<Teller> tellers = new ArrayList<Teller>();
Generators.fill(tellers, Teller.generator, 4);
for (Customer c : line) {
serve(tellers.get(random.nextInt(tellers.size())), c);
}
}
}
output:
Teller3serveCustomer1
Teller2serveCustomer2
Teller3serveCustomer3
Teller1serveCustomer4
Teller1serveCustomer5
Teller3serveCustomer6
Teller1serveCustomer7
Teller2serveCustomer8
Teller3serveCustomer9
Teller3serveCustomer10
Teller2serveCustomer11
Teller4serveCustomer12
Teller2serveCustomer13
Teller1serveCustomer14
Teller1serveCustomer15
Customer和Teller类都只有private的构造器,这可以强制你必须使用Generator对象(这里的Generator接口和Generators类都是前两篇博客出现的)。Customer有一个generator()方法,每次执行它都会生成一个新的Generator对象。由于Customer中的generator()方法,以及Teller中的Generator对象都声明成了static的,所以它们无法作为接口的一部分,因此无法用接口这种特定的惯用法来泛化这二者。尽管如此,它们在fill()方法中都工作得很好。
2.擦除的神秘之处
在泛型的代码内部,无法获得任何有关泛型参数类型的信息。因此,你可以知道诸如类型参数标识符和泛型类型边界这类的信息——你却无法知道用来创建某个特定实例的实际的类型参数。java泛型时使用擦除来实现的,这意味着当你再使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此List 和List在运行时事实上是相同的类型。这两种形式都被擦除成它们的“原生”类型,即List。
擦除主要的正当理由是从非泛化代码到泛化代码的转变过程,以及在不破坏现有类库的情况下,将泛型融入java语音。擦除使得现有的非泛型客户端代码能够在不改变的情况下继续使用,直至客户端准备好用泛型重写这些代码。擦除的代价是显著的。泛型不能用于显式地引用运行时类型的操作之中,例如转型、instanceof和操作和new表达式。