我有一个域类,其中有很多子类,如下所示(B是接口类型,B1和B2)实现了B接口。
正如您在我的主类中看到的那样,它需要强制转换(B1 b1 =(B1)a.getB();),我们知道它可以是B1或B2,所以就我所知应该是正确的。
我遇到的问题是类型可以增长很多,使用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
}
}
最佳答案
假设您确实需要此功能(上面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是很好的中级描述。