“嗨,阿米戈!”
“嗨,艾莉!”
“今天,Rishi 和我将向大家介绍仿制药。”
“等等,我想我几乎什么都知道了。”
“几乎所有,但不是所有。”
“真的吗?好吧,我准备好倾听了。”
“那我们开始吧。”
“在 Java 中,泛型是具有类型参数的类。”
“至于为什么要发明泛型,看代码中的注释:”
例子
ArrayList stringList = new ArrayList();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // Add a number to the list
for(Object o: stringList)
{
String s = (String) o; // There will be an exception here when we get to the integer
}
如何使用泛型解决问题:
例子
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // There will be a compilation error here
for(Object o: stringList)
{
String s = (String) o;
}
“这段代码根本无法编译,并且在编译期间会注意到由于添加错误的数据类型而导致的错误。”
“是的,我已经知道了。”
“好,好。重复是学习之母。”
“但是 Java 的创建者在创建泛型时有点懒惰。他们没有制作带有参数的完整类型,而是进行了巧妙的优化。实际上,他们没有向泛型添加任何有关类型参数的信息。相反,所有的编译过程中会发生魔法。”
泛型代码
List<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("abc");
strings.add( 1); // Compilation error
for(String s: strings)
{
System.out.println(s);
}
真正发生了什么
List strings = new ArrayList();
strings.add((String)"abc");
strings.add((String)"abc");
strings.add((String) 1); // Compilation error
for(String s: strings)
{
System.out.println(s);
}
“那很光滑。”
“是的,但是这种方法有一个副作用。 泛型类内部不存储类型参数的信息。 这种方法后来被称为类型擦除。”
“换句话说,如果你有自己的带有类型参数的类,你就不能在类中使用关于它们的信息。”
泛型代码
class Zoo<T>
{
ArrayList<T> pets = new ArrayList<T>();
public T createAnimal()
{
T animal = new T();
pets.add(animal)
return animal;
}
}
真正发生了什么
class Zoo
{
ArrayList pets = new ArrayList();
public Object createAnimal()
{
Object animal = new ???();
pets.add(animal)
return animal;
}
}
“在编译期间,所有参数类型都被替换为 Object。并且在类内部没有关于传递给它的类型的信息。”
“是的,我同意,那不是最好的。”
“没那么可怕,我稍后会告诉你如何解决这个问题。”
但还有更多。Java 允许您为类型参数指定父类型。extends 关键字用于此。例如:
泛型代码
class Zoo<T extends Cat>
{
T cat;
T getCat()
{
return cat;
}
void setCat (T cat)
{
this.cat = cat;
}
String getCatName() { return this.cat.getName(); }
}
真正发生了什么
class Zoo
{
Cat cat;
Cat getCat()
{
return cat;
}
void setCat(Cat cat)
{
this.cat = cat;
}
String getCatName() { return this.cat.getName(); }
}
“注意两个事实:”
“首先,你不能只传递任何类型作为参数——你只能传递 Cat 或继承 Cat 的类。”
“其次,在 Zoo 类内部,类型 T 的变量现在可以调用 Cat 类的方法。 右侧的列解释了原因(因为 Cat 将在任何有 T 的地方被替换)”
“是的。如果我们说 Cat 或 Cat 的子类作为类型参数传递,那么我们可以肯定类型 T 将始终具有 Cat 类的方法。”
“嗯,这很聪明。”
GO TO FULL VERSION