考虑下面的例子(OOP书籍中的典型例子):
我有一个动物班,每个动物都有很多朋友。
和子类,如狗,鸭,老鼠等,其中添加特定的行为,如bark(), quack()等。
下面是Animal类:
public class Animal {
private Map<String,Animal> friends = new HashMap<>();
public void addFriend(String name, Animal animal){
friends.put(name,animal);
}
public Animal callFriend(String name){
return friends.get(name);
}
}
下面是一些带有大量类型转换的代码片段:
Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());
((Dog) jerry.callFriend("spike")).bark();
((Duck) jerry.callFriend("quacker")).quack();
有没有办法我可以使用返回类型的泛型来摆脱类型转换,这样我就可以说
jerry.callFriend("spike").bark();
jerry.callFriend("quacker").quack();
下面是一些初始代码,其中返回类型作为从未使用过的参数传递给方法。
public<T extends Animal> T callFriend(String name, T unusedTypeObj){
return (T)friends.get(name);
}
是否有一种方法可以在不使用instanceof的额外参数的情况下在运行时找出返回类型?或者至少通过传递该类型的类而不是虚拟实例。
我知道泛型是用于编译时类型检查的,但是对此有解决方法吗?
你可以这样实现它:
@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
return (T)friends.get(name);
}
(是的,这是法律代码;参见Java泛型:仅定义为返回类型的泛型类型。)
返回类型将从调用者推断出来。但是,请注意@SuppressWarnings注释:它告诉您这段代码不是类型安全的。您必须自己验证它,或者您可以在运行时获得classcastexception。
不幸的是,你使用它的方式(没有将返回值分配给临时变量),唯一让编译器高兴的方法是像这样调用它:
jerry.<Dog>callFriend("spike").bark();
虽然这可能比强制转换要好一点,但正如David Schmitt所说,最好给Animal类一个抽象的talk()方法。
不。编译器无法知道jerry.callFriend("spike")将返回什么类型。此外,您的实现只是将强制转换隐藏在方法中,而没有任何额外的类型安全。考虑一下:
jerry.addFriend("quaker", new Duck());
jerry.callFriend("quaker", /* unused */ new Dog()); // dies with illegal cast
在这种情况下,创建一个抽象的talk()方法并在子类中适当地重写它会更好地为你服务:
Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());
jerry.callFriend("spike").talk();
jerry.callFriend("quacker").talk();
你可以这样实现它:
@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
return (T)friends.get(name);
}
(是的,这是法律代码;参见Java泛型:仅定义为返回类型的泛型类型。)
返回类型将从调用者推断出来。但是,请注意@SuppressWarnings注释:它告诉您这段代码不是类型安全的。您必须自己验证它,或者您可以在运行时获得classcastexception。
不幸的是,你使用它的方式(没有将返回值分配给临时变量),唯一让编译器高兴的方法是像这样调用它:
jerry.<Dog>callFriend("spike").bark();
虽然这可能比强制转换要好一点,但正如David Schmitt所说,最好给Animal类一个抽象的talk()方法。