java接口中的泛型方法如何将超级对象转换为具体的子类对象?
我有以下代码片段,它运行良好java接口中的泛型方法如何将超级对象转换为具体的子类对象?,java,generics,interface,polymorphism,Java,Generics,Interface,Polymorphism,我有以下代码片段,它运行良好 public class Test { public static void main(String[] args) { App app = new App(); app.setHandler(Apple.class, new AppleHandler()); app.setHandler(Banana.class, new BananaHandler()); app.process(new
public class Test {
public static void main(String[] args) {
App app = new App();
app.setHandler(Apple.class, new AppleHandler());
app.setHandler(Banana.class, new BananaHandler());
app.process(new Apple());
app.process(new Banana());
}
}
class Fruit {}
class Apple extends Fruit {}
class Banana extends Fruit {}
interface Handler<T extends Fruit> {
public void handle(T fruit);
}
class AppleHandler implements Handler<Apple> {
@Override
public void handle(final Apple fruit) {
System.out.println("This is an apple.");
}
}
class BananaHandler implements Handler<Banana> {
@Override
public void handle(final Banana fruit) {
System.out.println("This is a banana.");
}
}
class App {
Map<Class, Handler> handlerMap = new HashMap<>();
public void setHandler(Class clazz, Handler handler) {
handlerMap.put(clazz, handler);
}
public void process(Fruit fruit) {
Handler handler = handlerMap.get(fruit.getClass());
handler.handle(fruit);// HERE, how java convert Fruit object to concrete subclass object automatically?
}
}
公共类测试{
公共静态void main(字符串[]args){
App App=新App();
app.setHandler(Apple.class,新的AppleHandler());
app.setHandler(Banana.class,新的BananaHandler());
app.process(新苹果());
app.process(新香蕉());
}
}
水果类{}
苹果类扩展水果{}
类{}
接口处理程序{
公共空柄(T果);
}
类AppleHandler实现处理程序{
@凌驾
公共无效手柄(最终苹果果){
System.out.println(“这是一个苹果”);
}
}
类BananaHandler实现Handler{
@凌驾
公共空柄(最终香蕉果){
System.out.println(“这是一个香蕉”);
}
}
类应用程序{
Map handlerMap=新的HashMap();
公共void setHandler(类clazz,Handler){
handlerMap.put(clazz,handler);
}
公共无效流程(水果){
Handler=handlerMap.get(fruit.getClass());
handle.handle(fruit);//这里,java如何自动将fruit对象转换为具体的子类对象?
}
}
我希望
App
类以不同的方式处理不同的Fruit
,因此我定义AppleHandler
来处理Apple
,定义BananaHandler
来处理BananaHandler
。AppleHandler
和BananaHandler
都实现了一个通用接口Handler
,该接口具有通用方法handle
handle
方法在App.process
方法中被赋予一个Fruit
对象,具体的handle
方法将按预期被调用。当调用具体的handle
方法时,java似乎会自动将Fruit
对象转换为其实际类型。java是如何做到这一点的?代码之所以有效,是因为您在映射中使用处理程序来利用原始类型
通过使用原始类型,您可以获得类似于Map
,因此任何类型的对象都可以用于检索正确的处理程序。代码工作的事实仅仅是由映射器设置正确这一事实给出的。没有什么能阻止你这样做
app.setHandler(Apple.class, new BananaHandler());
app.setHandler(Banana.class, new AppleHandler());
这将产生一个ClassCastException
:
tests.Main$Apple cannot be cast to tests.Main$Banana
所以这里没有黑魔法,只要尝试使用泛型类型变量,您就会看到,如果不强制执行处理程序的类型,相同的代码将无法工作
由于类型擦除,您的AppleHandler
实现编译为
class AppleHandler {
void handle(Object object) {
Apple apple = (Apple)object;
System.out.println("This is an apple");
}
}
因此,从外部不需要强制转换就可以将结果分派到正确的处理程序,但这也意味着编译器无法确保在运行时分派是正确的
public void process(Fruit fruit) {
Handler handler = handlerMap.get(fruit.getClass());
在这里,参数是一个水果
,但实际的类是香蕉
。所以当你说fruit.getClass()返回香蕉时,它得到香蕉处理程序,我认为如果你去掉处理程序接口,把句柄()方法放在水果/苹果/…
中,这个例子会更好
在java中,我们通过引用变量访问对象(例如,typeT
),这是唯一的方法。一旦为对象(T或T的子类型)创建了ref变量,则无法更改引用变量的类型,可以将其重新分配给其他变量。引用变量的类型将决定它可以在对象上调用的方法
您使用new Apple()
创建一个对象,一个ref-var被声明给Apple对象,无论它是four a=new Apple()
还是Apple a=new Apple()
两者都引用Apple
的对象,即使以后您也会引用object o=a
,o
也指Apple
对象。所以如果你做了Fruit a=new Apple();a、 doSomething()
,java将找到Apple
对象,并执行Apple
类/对象的doSomething()
方法
似乎java在调用具体句柄方法时会自动将一个水果对象转换为它的真实类型。java是如何实现这一点的
这是正确的。编译器根据泛型参数插入强制转换。这在代码中很难看到,因为您使用了太多的原始类型
当您这样做时:
Handler handler = handlerMap.get(fruit.getClass());
handler.handle(fruit);
handler
的泛型参数未知,因此将fruit
传递给handle
方法的已擦除形式,如下所示:
public void handle(Fruit fruit)
因此代码可以编译。但是在这一点上,动态分派启动了一个调用句柄
的重写实现,例如您在AppleHandler
中定义的实现:
@Override
public void handle(final Apple fruit) {
System.out.println("This is an apple.");
}
此时,通用参数已知,参数被转换为Apple
此强制转换也可以在AppleHandler
类的字节码中看到:
public void handle(test.Fruit);
Code:
0: aload_0
1: aload_1
2: checkcast #35 // class test/Apple
5: invokevirtual #37 // Method handle:(Ltest/Apple;)V
8: return
你的问题是:Java是如何实现多态性的?@DavidChoweller,不是。我的问题是:当调用具体句柄方法(这称为多态性)时,Java是如何将水果对象转换为苹果或香蕉对象的?是的,你是对的。但是,Banana.handle被赋予了一个水果物体,它是如何以及何时铸造成香蕉物体的?@expoter no,你很困惑。这个过程得到了一个香蕉。香蕉是水果的一个子类,因此当调用process方法时,水果对象实际上是一个香蕉,而不是一个正在进行多态性的水果。没有转换发生。谢谢你的建议!