我怎样才能贬低到class级’E型或至少在没有警告的情况下安全地进行?
我有超级抽象类Node和50种子类SubNode。
我有一个通用的Class ,它有一个私有var List 和一个方法,不幸的是它必须接受超类Node ALWAYS,不能将它移动到E:
public void addSubElement (Node node){ if (node instanceOf E) subElements.add((E)node); else //Doing extra steps for occasional non-E nodes like discarding them silently without CastException; }
任何解决方案(Reflection?)能够在没有警告的情况下编译,抛出CastException而不是因为类型擦除而添加任何对象?? …
我不想为任何类型的子类编写相同的函数:
public void addSubElement (Node node){ if (node instanceOf SubNode1) subElements.add((SubNode1)node); if (node instanceOf SubNode2) subElements.add((SubNode2)node); //if (node instanceOf SubNode50.... }
有一个像这样的方法会很好。
public void addSubElement (Node node){ subElements.add((E)node.autoCastToSubClassOfAbstract("Node")); //Should throw CastException if non-E }
要么
public void addSubElement (Node node){ subElements.add(node.autoCastTo("E")); //Should throw CastException if non-E }
如果你被迫以某种方式拥有一个
public void addSubElement (Node node);
那么你唯一的选择就是使用
public void addSubElement (Node node){ subElements.add((E)node); }
如果没有得到警告(你当然可以压制),就没有办法实现这一点。
这是好的,只要你是唯一一个使用这种方法的人,你可以忽略警告,只要你确保总是用正确的参数调用它。
你的设计有缺陷。 方法的签名应该是:
public void addSubElement (E node)
或subElements
应为List
类型而不是List
。
假设您的类是NodeList
,然后您创建一个实例:
NodeList nl = new NodeList ();
然后列表将只接受SubNode1
实例,因此您将无法做到
nl.addSubElement(subNode2Instance)
更新:
我找到的唯一解决方法是:
private static class G { private E templateObject; private List subElements = new ArrayList (); public G(E templateObject) { this.templateObject = templateObject; } public void addSubElement (NodeB node) { if (templateObject.getClass().isAssignableFrom(node.getClass())) { subElements.add((E) node); } else { throw new ClassCastException(); } } }
使用generics时,有些情况下您无法在不抑制警告的情况下编写有效代码。
针对您的问题的纯OO方法是为每种类型编写addSubElement()
方法。 这将为每种类型(N * N)提供每种类型一种方法。 您可以在相应类型中添加特殊情况。
显然,对于任何大量不同类型(比如说超过三种),方法的数量会迅速爆炸,你会发现自己处于需要剪切和粘贴大量代码的情况。
即使您只需要编写其中的一些并将大部分工作委托给通用的addSubElement(Node)
方法,它仍然会产生技术债务,因为您需要为每种新类型编写X方法。
因此,对于你的角落案例,可能无法绕过instanceof
和@SuppressWarnings("unchecked")
。
[编辑]
您可以定义Node
必须实现的接口INode
。 你的课程可能如下所示:
public Node { @SuppressWarnings("unchecked") public void addSubElement(N n) { ... } }
此模式允许您限制此实现接受的节点的可能类型,或者使用Node
for N
来接受任何内容以及在方法中进行特殊处理的内容。
这里的优点是,当您将类型传递给无法处理它的实现时,您可能会遇到编译时错误。 但是你仍然需要在方法中使用强制转换来抑制警告。
编辑:所有其他答复的最终答案:
如果接受titofb回答,我会犹豫不决,因为他是指定好方法的人。 但是我觉得这个问题足以针对我自己的问题(第一次),为了阅读它的其他人的利益。 谢谢大家!
抽象Node类实现了这个:
@SuppressWarnings("unchecked") protected final Class getChildType(){ return (Class )(((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]); }
所以任何Subnode总是有一个可用的方法,它从定义中返回自己的Type E SubnodeN扩展Node
public void addSubElement (Node> node){ Class expectedChildType = getChildType(); if (expectedChildType.isAssignableFrom(node.getClass())){//if node instanceOf E subElements.add(expectedChildType.cast(node)); } else throw new ClassCastException("A non-expected child was intended to add to this "+this.getClass().getSimpleName()+" element"); }
然后在这里它是神奇的。 这是默认行为。 如果不期望某个孩子,它会发出警告,但您可以为任何子节点覆盖此方法以处理特殊情况:
@Override public void addSubElement (Node> node){ if (node instanceOf SubNode34) {/* Yes, our current subnode does not expect all elements intended to be added as E type nodes, we can silently discard or do whatever */} else super.addSubElement(node) //Parents default behavior }