在 Java 中将对象转换为其子类
Transform an object to its subclass in Java
这不是一般问题,请听我解释。
我有一个对象class Animal
。我怎样才能把它转换成它的subclass Cat
?像这样:
Animal a = new Animal();
Cat c = (Cat) a;
当然,我知道从Animal
直接转换到Cat
是不可能的。但我不想手动创建一个新的 Cat
并将字段从 Animal
复制到它。因为有时我有很多 class 层次结构需要转换。怎么用通用的方法解决?
在子class中创建一个复制构造函数如何?
public Cat(Animal animal) { super(animal); }
在 Animal
class 中声明这样的构造函数,然后使用 super(animal)
从任何子 class 向其传递一个控件,您将在其中定义自定义逻辑。
忽略了这样一个事实,即在您的示例中您想要反转原样关系(如 "an apple is-a fruit" 与 "a fruit is-an apple" 中的关系)——这在某种程度上毫无意义。
但是让我们想象一下这样的情况,您必须让土豆 看起来像 苹果。所以你要做的是切掉所有果肉并将土豆放入苹果中(我在这里使用水果示例,因为对于动物来说它会变得有点混乱)。
这称为代理或包装。
这两种技术都可以在 java 中静态或动态地完成。
静态:包装器:
- 新建 Class,即 VeggiAppleWrapper
- 让它扩展苹果(所以它包裹的任何东西看起来都像苹果)
- 定义接受其他类型(即 Potato)的构造函数
- implement/override 常用方法并将调用委托给包装对象
- 实施抛出 UnsupportedOperationException 的所有其他方法
动态地:代理:
- 你必须至少为目标类型定义一个接口(即
interface Apple
)
- 使用Proxy
创建代理实例
- 使用已实现接口列表中的
Apple
接口
- 实现一个
MethodInvocationHandler
来为您转发,类似于 Wrapper,但使用 Reflection
- 将代理投射到
Apple
使用 Java 的动态代理的替代方法是代码生成库,例如 CGLib or Javaassist,它会在运行时生成目标类型的子 class,这与包装器但像代理一样实现。
为了仅将值从 animal 复制到 cat 实例(因为 animal 是一个超级class,一些字段应该是通用的),您也可以使用反射 api
for(Field f : Animal.class.getDeclaredFields()) {
f.setAccessible(true)
f.set(cat, f.get(animal));
}
这只是一个简单的例子,没有异常处理,也没有考虑Animal的superclass的字段(getDeclaredFields
只检索了this的字段class).
我觉得你做的对
Animal animal = new Animal();
Cat cat = new Cat();
public void foo(){
animal = cat; //works because Animal is parent class
cat = (Cat) animal; //you cast Animal to Cat like as parent to child
}
看看这个https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
希望对你有帮助
这不是一般问题,请听我解释。
我有一个对象class Animal
。我怎样才能把它转换成它的subclass Cat
?像这样:
Animal a = new Animal();
Cat c = (Cat) a;
当然,我知道从Animal
直接转换到Cat
是不可能的。但我不想手动创建一个新的 Cat
并将字段从 Animal
复制到它。因为有时我有很多 class 层次结构需要转换。怎么用通用的方法解决?
在子class中创建一个复制构造函数如何?
public Cat(Animal animal) { super(animal); }
在 Animal
class 中声明这样的构造函数,然后使用 super(animal)
从任何子 class 向其传递一个控件,您将在其中定义自定义逻辑。
忽略了这样一个事实,即在您的示例中您想要反转原样关系(如 "an apple is-a fruit" 与 "a fruit is-an apple" 中的关系)——这在某种程度上毫无意义。
但是让我们想象一下这样的情况,您必须让土豆 看起来像 苹果。所以你要做的是切掉所有果肉并将土豆放入苹果中(我在这里使用水果示例,因为对于动物来说它会变得有点混乱)。 这称为代理或包装。
这两种技术都可以在 java 中静态或动态地完成。
静态:包装器:
- 新建 Class,即 VeggiAppleWrapper
- 让它扩展苹果(所以它包裹的任何东西看起来都像苹果)
- 定义接受其他类型(即 Potato)的构造函数
- implement/override 常用方法并将调用委托给包装对象
- 实施抛出 UnsupportedOperationException 的所有其他方法
动态地:代理:
- 你必须至少为目标类型定义一个接口(即
interface Apple
) - 使用Proxy 创建代理实例
- 使用已实现接口列表中的
Apple
接口 - 实现一个
MethodInvocationHandler
来为您转发,类似于 Wrapper,但使用 Reflection - 将代理投射到
Apple
使用 Java 的动态代理的替代方法是代码生成库,例如 CGLib or Javaassist,它会在运行时生成目标类型的子 class,这与包装器但像代理一样实现。
为了仅将值从 animal 复制到 cat 实例(因为 animal 是一个超级class,一些字段应该是通用的),您也可以使用反射 api
for(Field f : Animal.class.getDeclaredFields()) {
f.setAccessible(true)
f.set(cat, f.get(animal));
}
这只是一个简单的例子,没有异常处理,也没有考虑Animal的superclass的字段(getDeclaredFields
只检索了this的字段class).
我觉得你做的对
Animal animal = new Animal();
Cat cat = new Cat();
public void foo(){
animal = cat; //works because Animal is parent class
cat = (Cat) animal; //you cast Animal to Cat like as parent to child
}
看看这个https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
希望对你有帮助