我有一个由两个具体类继承的抽象类。
public abstract class AbstractClass {
public abstract void operation1();
}
public class ConcreteClassA extends AbstractClass {
@Override
public void operation1() {
// Do work
}
public void operation2() {
// Do some other work
}
}
public class ConcreteClassB extends AbstractClass {
@Override
public void operation1() {
// Do work
}
}
现在,为了利用动态绑定,我在编程接口时创建了两个对象。
private AbstractClass classA = new ConcreteClassA();
private AbstractClass classB = new ConcreteClassB();
但这不允许我在operation2()
上调用方法classA
。我可以通过使用垂头丧气来解决这个问题。
((ConcreteClassA) classA).operation2();
但是在OOP中,垂头丧气被认为是丑陋的,特别是当你不得不经常使用它们时。或者,我可以放弃对界面的编程。
private ConcreteClassA classA = new ConcreteClassA();
但后来我失去了动态绑定。另一种选择是将operation2()
移至AbstractClass
,以便我可以恢复动态绑定。
public abstract class AbstractClass {
public abstract void operation1();
public abstract void operation2();
}
但是ConcreteClassB
需要覆盖operation2()
,使实现为空,因为这个类不需要这个方法。
最后,我可以将operation2()
移到AbstractClass
并提供可以覆盖或不覆盖的默认实现。
public abstract class AbstractClass {
public abstract void operation1();
public void operation2() {
// Some default implementation
}
}
但这会让classB
访问operation2()
,我宁愿避免。
在保持动态绑定的同时调用子类特定方法似乎没有一个干净的解决方案。或者有吗?
答案 0 :(得分:1)
至少有几种方法可以解决这种情况,实际上,正确的方法取决于您的特殊要求。
问问自己,“我的类型指定的合同中是operation1和operation2的一部分吗?”
如果答案显然不是,那么您不应该通过添加附带方法来污染您的类型合同。接下来你应该问自己,“为什么我不使用接口来指定单独的类型,例如:而不是AbstractClass
,为什么我不使用MyInterface1
和MyInterface2
(每个都有自己的单独的契约)?接口提供有限形式的多重继承,您的实现类可以实现与其相关的任何和所有接口。这是Java平台库常用的策略。在这种情况下,显式转换为其类型你想要使用的合同是正确的。
如果答案显然是肯定的,那么你的类型应该有两种方法......但你仍然应该问自己,“为什么我没有用界面指定我的类型”?通常,您应该使用接口而不是抽象类来指定类型,但是有理由使用后者。
如果答案介于两者之间,那么您可以考虑在类型中指定可选方法。这些方法包含在您的类型的合同中,但实现类不需要实现。在Java 8之前,每个实现类型都需要为它未实现的任何可选方法抛出UnsupportedOperationException
。在Java 8中,您可以对可选方法执行类似的操作:
==
public interface MyType {
void contractOperation1();
default void optionalOperation2() {
throw new UnsupportedOperationException();
}
}
实现此接口的类需要为contractOperation1()
提供实现。但是,该类不需要为optionalOperation2()
提供实现,如果在没有提供自己的实现的实现类上调用此方法,则默认情况下会抛出异常。
答案 1 :(得分:-1)
抽象类没有对象,我们只是创建该类的引用并使用它。
像: 而不是这个 -
private AbstractClass classA = new ConcreteClassA();
private AbstractClass classB = new ConcreteClassB();
使用这个
private AbstractClass classA;
private AbstractClass classB;
如果我们要创建抽象类的对象并调用没有主体的方法(因为该方法是纯虚拟的),它将给出错误。这就是为什么我们不能创建抽象类的对象。这是一个类似的StackOverflow问题。简而言之,在抽象类上使用公共构造函数是合法的。