我有一个域类,它有很多子节点,如下所示(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
}
}
答案 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。
使用基类型作为对象的引用有许多优点:
答案 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{
}
或
执行方法覆盖并且可以为不同的类实现不同的逻辑,并且可以使用接口引用调用方法而不使用任何转换