Java 将最后一个类强制转换为该类未声明实现的兼容接口

Java 将最后一个类强制转换为该类未声明实现的兼容接口,java,interface,casting,duck-typing,Java,Interface,Casting,Duck Typing,有时在Java中,您会使用一个库来提供最终类Car,您希望它实现一些车辆接口,这样您就可以创建卡车和总线类,并在代码中将它们都视为车辆。但Car是最终版本,它不实现任何接口 如何将其他人的最终汽车类转换到我的汽车界面,以便我可以像其他汽车一样传递它?车辆上的每个实例方法在实例方法名称、参数类型和返回类型方面都与车辆上的类似方法100%兼容。从Duck类型的角度来看,它是等效的 我知道我可以创建一个mycarextensedvehiclewrapper类,它只将每个方法调用委托给一个内部Car对象

有时在Java中,您会使用一个库来提供
最终类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);
         }

    }

}
  • 类中的最终修饰符不允许更改其状态,因此它是无法修改该类的

  • Cast将只对您有效如果您从父类或实现扩展到接口,则没有其他方法(但您不能,因为类是最终的)

  • 在这种情况下,您有三种选择: 1.包装器(你提到的)。 2.反射(您可以在运行时找出有关类及其方法的有用信息)。 3.创建自己的类


  • 不,包装器解决方案(组合)是唯一的方法。您可以使用JDK代理接口。@PaulBoddington,但可以动态生成。OP想要的是自定义字节码生成和InvokeDynamic(groovy和scala就是这样做的),但您不能从java源代码使用它。最好的办法是使用JDK代理对象动态生成包装器,这样就可以创建一个库,比如
    Vehicle carVehicle=DuckTyper.quack(car,Vehicle.class)我不知道这个具体的例子,但是Groovy应该生成一个JDK代理(或者等效的动态类)。对不起,这真的不值得一个“答案”。如果您需要解释为什么这是唯一的方法。此外,您需要
    实现车辆
    -这是一个接口。
    Vehicle carVehicle = DuckTyper.quack(car, Vehicle.class);