Java 将最后一个类强制转换为该类未声明实现的兼容接口
有时在Java中,您会使用一个库来提供Java 将最后一个类强制转换为该类未声明实现的兼容接口,java,interface,casting,duck-typing,Java,Interface,Casting,Duck Typing,有时在Java中,您会使用一个库来提供最终类Car,您希望它实现一些车辆接口,这样您就可以创建卡车和总线类,并在代码中将它们都视为车辆。但Car是最终版本,它不实现任何接口 如何将其他人的最终汽车类转换到我的汽车界面,以便我可以像其他汽车一样传递它?车辆上的每个实例方法在实例方法名称、参数类型和返回类型方面都与车辆上的类似方法100%兼容。从Duck类型的角度来看,它是等效的 我知道我可以创建一个mycarextensedvehiclewrapper类,它只将每个方法调用委托给一个内部Car对象
最终类Car
,您希望它实现一些车辆
接口,这样您就可以创建卡车
和总线
类,并在代码中将它们都视为车辆。但Car是最终版本,它不实现任何接口
如何将其他人的最终汽车
类转换到我的汽车
界面,以便我可以像其他汽车一样传递它?车辆上的每个实例方法在实例方法名称、参数类型和返回类型方面都与车辆上的类似方法100%兼容。从Duck类型的角度来看,它是等效的
我知道我可以创建一个
mycarextensedvehicle
wrapper类,它只将每个方法调用委托给一个内部Car对象。这就是Java的方式。但我只是想知道是否有一种技术可以将一个类转换为一个不相关(但100%兼容)的接口。如果答案是邪恶的,那没关系。正如您所提到的,我个人会为它创建一个包装类。也许参考一下
汽车
界面会有所帮助
public abstract class MyCar implements Vehicle {
private Car car;
(...)
}
没有很多方法可以做到这一点,我不确定我的方法是否符合您的要求,也不确定它是否完全有效。使用代理执行:
import java.lang.reflect.Proxy;
public class DuckTyping {
static final class Car{
public void honk(){
System.out.println("honk");
}
}
interface Vehicle{
void honk();
}
public static void main(String[] a){
Car c = new Car();
Vehicle v = (Vehicle) Proxy.newProxyInstance(Vehicle.class.getClassLoader(), new Class[]{Vehicle.class}, (proxy, method, args) ->
Car.class.getMethod(method.getName(), method.getParameterTypes()).invoke(c, args)
);
v.honk();
}
}
一般方法:
static <T> T proxyCast(Object targetObject, Class<T> targetClass) {
return (T) Proxy.newProxyInstance(targetClass.getClassLoader(), new Class[]{targetClass}, (proxy, method, args) ->
targetObject.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(targetObject, args)
);
}
static T proxyCast(对象targetObject,类targetClass){
返回(T)Proxy.newProxyInstance(targetClass.getClassLoader(),新类[]{targetClass},(代理,方法,参数)->
targetObject.getClass().getMethod(method.getName(),method.getParameterTypes()).invoke(targetObject,args)
);
}
最简单的方法是使用JDK代理:
public class DuckTyper {
public static <T> T quack(Object target, Class<T> duck) {
return (T) Proxy.newProxyInstance(duck.getClassLoader(), new Class[] { duck }, new DuckCostume(target));
}
private static class DuckCostume implements InvocationHandler {
private final Object target;
public DuckCostume(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());
return targetMethod.invoke(target, args);
}
}
}
不,包装器解决方案(组合)是唯一的方法。您可以使用JDK代理接口。@PaulBoddington,但可以动态生成。OP想要的是自定义字节码生成和InvokeDynamic(groovy和scala就是这样做的),但您不能从java源代码使用它。最好的办法是使用JDK代理对象动态生成包装器,这样就可以创建一个库,比如
Vehicle carVehicle=DuckTyper.quack(car,Vehicle.class)代码>我不知道这个具体的例子,但是Groovy应该生成一个JDK代理(或者等效的动态类)。对不起,这真的不值得一个“答案”。如果您需要解释为什么这是唯一的方法。此外,您需要实现车辆
-这是一个接口。
Vehicle carVehicle = DuckTyper.quack(car, Vehicle.class);