我怎么能向下转换类的类型E或者至少使其在安全,没有警告?(How can I downcast to

2019-06-26 11:10发布

我有超级抽象类节点和50种亚类子节点。

我有一个泛型类<E扩展节点>其中有一个私人变种名单<E>和不幸有始终接受父节点的方法,不能移动它只是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; 
 }

任何解决方案(反射?)能编译没有警告,扔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
 }

Answer 1:

如果你以某种方式被迫

public void addSubElement (Node node); 

那么你唯一的选择是使用

public void addSubElement (Node node){ 
    subElements.add((E)node); 
}

有没有办法实现这一目标没有得到一个警告(你当然可以抑制)。

这是罚款,只要你使用这种方法只有一个,你可以忽略这个警告,只要你确保始终以正确的参数调用它。



Answer 2:

你在你的设计中的缺陷。 无论是方法的签名应该是:

public void addSubElement (E node)

subElements应该是类型的List<Node>代替List<E>

比方说,你的类是NodeList<E extends Node> ,然后创建一个实例:

NodeList<SubNode1> nl = new NodeList<SubNode1>();

然后,该列表将只接受的情况下SubNode1 ,这样你就不会能够做到

nl.addSubElement(subNode2Instance)

更新:

我发现的唯一的解决方法是这样的:

private static class G<E extends NodeB> {

    private E templateObject;

    private List<E> subElements = new ArrayList<E>();

    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();
        }
    }

}


Answer 3:

当使用泛型,还有角落情况下,你不能没有抑制警告编写有效的代码。

有关问题的纯面向对象的方法是在写addSubElement()为每种类型的方法。 这将使你每一个类型的方法在每个类型(N * N)。 你可以在相应类型添加特殊情况。

显然,对于不同类型的任何显著号(说三个以上),方法的数量迅速爆炸,你会发现自己在那里你必须复制粘贴大量的代码的情况。

即使你只需要编写一些他们并委托大部分工作提高到一个通用的addSubElement(Node)的方法,但它仍然会造成技术的债务,因为你需要写为每个新的X型的方法。

因此,对于你的角落的情况下,有可能是周围也没有路instanceof@SuppressWarnings("unchecked")

[编辑]

你可以定义一个接口INode ,其Node必须实现。 然后,您的类可以是这样的:

public Node<E,N extends INode> {

    @SuppressWarnings("unchecked")
    public void addSubElement(N n) { ... }
}

这种模式将让您无论是限制可能的类型此实现接受节点或使用NodeN的东西,接受任何东西,在那里你在做的方法进行特殊处理。

这里的好处是,你可以得到,当你传递一个类型,它不能处理它的实现编译时错误。 但是,你仍然需要在方法铸造并抑制警告。



Answer 4:

编辑:最后的答案与所有其他解答:

,我当时犹豫是否接受titofb答案beause他是谁任命的好办法之一。 但我认为这是不够的目标上应该aceptŸ问题我自己(非常1次),为他人谁读它的好处。 谢谢大家!

抽象节点类实现这一点:

    @SuppressWarnings("unchecked")
    protected final Class<E> getChildType(){
        return (Class<E>)(((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]); 
    }

因此,任何具有子节点总是从定义SubnodeN返回自己的E型可用的方法扩展节点<SubNodeX>(SubnodeX = N在节点<E>)。 这意味着,我们可以做到在任何节点:

 public void addSubElement (Node<?> node){ 
      Class<E> 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
 }    


文章来源: How can I downcast to class' type E or at least make it in a safe way without warnings?