Java 根据实际对象类型动态参照转换
我有一些类,比如Java 根据实际对象类型动态参照转换,java,dynamic,reflection,Java,Dynamic,Reflection,我有一些类,比如 ChildA extends Parent ChildB extends Parent ChildC extends Parent 然后在我的应用程序中,我通过父引用在一个方法中获取这个子对象的任何一个 if (parent instanceof ChildA) { ChildA childA = (ChildA) parent; } else if (parent instanceof ChildB) { ChildB chi
ChildA extends Parent
ChildB extends Parent
ChildC extends Parent
然后在我的应用程序中,我通过父引用在一个方法中获取这个子对象的任何一个
if (parent instanceof ChildA) {
ChildA childA = (ChildA) parent;
} else if (parent instanceof ChildB) {
ChildB childB = (ChildB) parent;
} else if (parent instanceof ChildC) {
ChildC childAC = (ChildC) parent;
}
问题是所有这些孩子都有相同的方法,但他们的父母没有
因此,ChildA、ChildB和ChildC
都有getSomeValue()
getter,但Parent
没有
现在,我需要解析来自任何子级的值,但是父级引用没有为我提供API,所以我需要将父级强制转换为特定的子级类型
下面是我试图做的事情的片段:
private void processChildren(Parent parent) {
ChildA childA = null;
ChildB childB = null;
ChildC childC = null;
if (parent instanceof ChildA) {
childA = parent;
}
if (parent instanceof ChildB) {
childB = parent;
}
if (parent instanceof ChildC) {
childC = parent;
}
String someValue;
if (Objects.nonNull(childA)) {
someValue = childA.getSomeValue();
} // and the same checks and extracts for each of childs and for many methods
}
如您所见,为了只提取一个值,我需要创建3个引用,然后检查它们以转换为特定类型,然后检查实际创建的类型以调用该方法
问题是如何在运行时正确地将引用转换为特定的子引用?
我想使用反射来写作是可能的,尽管我甚至不能用反射来解决它
还有,即使有可能,这样做可以吗
仅供参考:我正在处理一个遗留应用程序,因此无法更改以前编写的代码,因此无法在父类中添加此API。此外,这些类是从外部jar提供的
问题是如何正确地投下绝对正确的参考
这种类型中的哪一种是特定的参考
使用instanceof运算符检查父引用的确切实例类型
if (parent instanceof ChildA) {
ChildA childA = (ChildA) parent;
} else if (parent instanceof ChildB) {
ChildB childB = (ChildB) parent;
} else if (parent instanceof ChildC) {
ChildC childAC = (ChildC) parent;
}
如果您确定所有的子对象都有getSomeValue方法,那么您可以将它们称为
parent.getClass().getMethod("getSomeValue").invoke(parent);
然而,这不是一个好的做法。类设计违反了Liskov的替换原则。我的方法是通过缺少的接口扩展父类。为此,我定义了一个接口来声明缺少的方法:
public interface HasSomeValue {
String getSomeValue();
}
由于不可能让Parent
本身实现这个接口,我为Parent
定义了一个包装器:
private static class ParentWithSomeValue implements HasSomeValue {
private Parent parent;
public ParentWithSomeValue(Parent parent) {
this.parent = parent;
}
@Override
public String getSomeValue() {
try {
Method method = parent.getClass().getMethod("getSomeValue");
return (String) method.invoke(parent);
} catch (Exception e) {
return null;
}
}
}
而且ParentWithSomeValue
将委托给Parent
已经拥有的其他方法。然后ParentWithSomeValue
提供了Parent
的完整接口,可以替换它
getSomeValue
使用反射实现。如果parent
具有被调用的方法,则使用反射将调用委派给parent
。否则将返回默认值。在我的示例中,null
。另一个选项是,如果parent
必须有被调用的方法,则抛出异常
使用这种方法,您还可以扩展已实现的接口或添加更多接口,并基于每个方法实现委派
将此应用于代码:
private void processChildren(Parent parent) {
if (Objects.nonNull(parent)) {
ParentWithSomeValue parentWithSomeValue = new ParentWithSomeValue(parent);
String someValue = parentWithSomeValue.getSomeValue();
// go on
}
}
作为一种可能的解决方案,您可以创建一个由特定子类参数化的映射作为键,并将供应商作为值。每个供应商负责铸造和处理特定方法
Map<Class<? extends Parent>, Supplier> getValueMap = new HashMap<>();
getValueMap.put(ChildA.class, () -> { return ((ChildA) parent).getValue(); });
getValueMap.put(ChildB.class, () -> { return ((ChildB) parent).getValue(); });
getValueMap.put(ChildC.class, () -> { return ((ChildC) parent).getValue(); });
getValueMap.get(parent.getClass()).get();
map能否将父类的引用更改为子类从中扩展的其他子类?类似于ChildA-->SubParent-->Parent您可以使用instanceof运算符来检查确切的实例类型您可以添加一个代码示例,说明如何通过父引用在该子对象上的任何方法中获得任何值吗?getSomeValue()
的返回类型是什么?这有关系吗?StringHi,谢谢,但这个问题包含“正确”这个词,所以若我有一百个孩子,那个么用你们的解决方案,我会有一个很长的方法。我正在寻找一个好的解决方案,你能像我在前面的评论中所问的那样对父类进行子类化吗?ChildA-->SubParent-->Parent,然后在应用程序中使用SubParent引用而不是父引用。对不起,这些类是从外部jar提供的,因此我没有访问它们的权限。您的意思是所有类,即所有子类和父类都来自外部jar吗?是的。我可以用任何方式使用它们,但不能改变哇!伟大的解决方案!:)尽管您必须在映射中为每个子类创建条目。