考虑这个例子(在OOP书中很典型):
我有一个Animal
类,每个Animal
可以有很多朋友。
以及像Dog
,Duck
,Mouse
等添加特定行为的子类,如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
计算出运行时的返回类型?或者至少通过传递该类型的类而不是伪实例。
我知道泛型是用于编译时类型检查的,但是有没有解决这个问题的办法呢?
发布于 2009-01-16 07:57:35
您可以这样定义callFriend
:
public <T extends Animal> T callFriend(String name, Class<T> type) {
return type.cast(friends.get(name));
}
然后这样叫它:
jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();
这段代码的好处是不会生成任何编译器警告。当然,这实际上只是从前通用时代的转换的更新版本,并没有增加任何额外的安全性。
发布于 2009-01-16 07:50:05
不是的。编译器无法知道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();
发布于 2009-01-16 07:51:54
您可以像这样实现它:
@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
return (T)friends.get(name);
}
(是的,这是法律代码;请参阅Java Generics: Generic type defined as return type only。)
返回类型将从调用方推断出来。但是,请注意@SuppressWarnings
注释:它告诉您这段代码不是类型安全的。您必须自己验证它,否则您可能会在运行时获得ClassCastExceptions
。
不幸的是,您使用它的方式(没有将返回值赋给临时变量),让编译器满意的唯一方法就是这样调用它:
jerry.<Dog>callFriend("spike").bark();
虽然这可能比强制转换好一点,但正如David Schmitt所说的那样,最好为Animal
类提供一个抽象的talk()
方法。
https://stackoverflow.com/questions/450807
复制相似问题