需要设计建议来跳过对象类型转换

时间:2013-09-07 06:04:40

标签: java oop casting polymorphism

我有一个域类,它有很多子节点,如下所示(B是接口类型,B1和B2)实现B接口。

正如你在我的主类中看到的,它需要强制转换(B1 b1 =(B1)a.getB();)并且我们知道它可以是B1或B2,所以它应该对我的知识没有意义。< / p>

我遇到的问题是类型可以增长很多,使用A的人需要提供更多条件来检查B的实例并访问B1或B2的特定值... 我有什么方法可以跳过此投射,以便将来减少很多条件

public class TestMain
{
  public static void main(String[] args)
  {
    A a = new A();
    //this can be B1 or B2 
    B1 b1 = (B1) a.getB();
  }
}

public class A
{
  private B b;

  protected B getB()
  {
    return b;
  }

  protected void setB(B b)
  {
    this.b = b;
  }
}

public interface B
{
  void test();
}

public class B1 implements B
{
  @Override
  public void test()
  {
    // TODO Auto-generated method stub
  }
}
public class B2 implements B
{
  @Override
  public void test()
  {
    // TODO Auto-generated method stub
  }
}

4 个答案:

答案 0 :(得分:2)

假设你真的需要这个功能(以上Eran的评论提出了一个好点;多态可能会做你需要的大部分或全部),答案是泛型。它们是一个稍微高级的主题,但它们是Java的核心(JDK中的所有集合类都使用它们),因此它们非常重要。

泛型是一种说“某种类型”的方式,也可以选择“某种类型,这是某种其他类型的子类型”。后者就是你想要的。

public class A<T extends B>
{
  private T b;

  protected T getB()
  {
    return b;
  }

  protected void setB(T b)
  {
    this.b = b;
  }
}

<T extends B>部分声明T的泛型参数,并说它必须是B的子类。从那时起,您可以使用T,就像它是A类中的类型一样。对于此类的用户,他们必须指定它是什么类型的A,编译器将自动为您执行向下转换:

A<B1> a = new A<B1>();
a.set(new B1());
B1 b = a.getB();

请注意,在第二行中,如果您已完成a.set(new B2()),则会出现编译时错误:编译器会抱怨a已参数化为B1,因此您无法将B2传递给它。在很高的层次上,您可以想象编译器正在进行搜索和替换,用T替换原始类中的B1。如果你宣布:

A<B2> a = new A<B2>();

然后搜索和替换同样会将T变为B2

实际上,由于被称为擦除的东西,它并不那么简单。您可以在Java trail on generics阅读更多内容,还有许多其他资源可供使用。 This PDF是一个很好的中级描述。

答案 1 :(得分:1)

您也可以在不进行投射的情况下执行以下操作。

B b1 = a.getB();

答案 2 :(得分:0)

执行向下转换时,需要显式添加强制转换。向上投射是隐含的,而且总是安全的。另外,为什么需要将其明确地转换为B1或B2。而是您可以使用它作为对象的基础接口类型(即B),这不需要您添加演员表。

同样基于引用类型是安全的,因为您不必担心实际的对象类型,因此在运行时阻止ClassCastException。

使用基类型作为对象的引用有许多优点:

  • 在运行时避免使用ClassCastException。
  • 您无需担心添加演员
  • 此外,如果向基类层次结构添加更多类,则仍可以使用基本引用类型访问这些类。这使您的设计更加灵活。

答案 3 :(得分:0)

public class Test {
    public static void main(String[] args) {
        B b = new B1();
        if(B1.class.getName().equals(b.getClass().getName())){
            // implement logic for B1 class
        }else if(B1.class.getName().equals(b.getClass().getName())){
            // implement logic for B2 class         
        }
    }
}

interface B{    
}

class B1 implements B{  
}

class B2 implements B{  
}

执行方法覆盖并且可以为不同的类实现不同的逻辑,并且可以使用接口引用调用方法而不使用任何转换