为什么Java类不能像抽象方法一样具有抽象字段?
例如:我有两个扩展相同抽象基类的类。这两个类每个都有一个相同的方法,除了一个String常量,它常常是一个错误消息。如果字段可以是抽象的,我可以使这个常量抽象,并将方法拉入基类。相反,我必须创建一个抽象方法,在这种情况下称为getErrMsg()
,返回String,在两个派生类中重写此方法,然后我可以拉出方法(现在调用抽象方法)
为什么我不能开始抽象字段? Java可以设计为允许这个吗?
答案 0 :(得分:88)
您可以通过在抽象类中使用在其构造函数中初始化的最终字段(未经测试的代码)来执行您所描述的操作:
abstract class Base {
final String errMsg;
Base(String msg) {
errMsg = msg;
}
abstract String doSomething();
}
class Sub extends Base {
Sub() {
super("Sub message");
}
String doSomething() {
return errMsg + " from something";
}
}
如果你的子类“忘记”通过超级构造函数初始化final,编译器会给一个警告一个错误,就像没有实现抽象方法一样。
答案 1 :(得分:6)
我认为没有任何意义。您可以将该函数移动到抽象类,只需覆盖一些受保护的字段。我不知道这是否适用于常量但效果是一样的:
public abstract class Abstract {
protected String errorMsg = "";
public String getErrMsg() {
return this.errorMsg;
}
}
public class Foo extends Abstract {
public Foo() {
this.errorMsg = "Foo";
}
}
public class Bar extends Abstract {
public Bar() {
this.errorMsg = "Bar";
}
}
所以你的观点是你想在子类中强制执行/覆盖/ errorMsg
的任何内容?我以为你只是想在基类中使用该方法,然后不知道如何处理该字段。
答案 2 :(得分:3)
显然可以设计为允许这样做,但是在掩护下它仍然需要进行动态调度,因此需要进行方法调用。 Java的设计(至少在早期)在某种程度上是一种极简主义的尝试。也就是说,设计师试图避免添加新功能,如果它们可以通过语言中的其他功能轻松模拟。
答案 3 :(得分:0)
阅读你的标题,我以为你指的是抽象实例成员;我看不出他们有多大用处。但抽象的静态成员完全是另一回事。
我经常希望我能在Java中声明如下的方法:
public abstract class MyClass {
public static abstract MyClass createInstance();
// more stuff...
}
基本上,我想坚持我父类的具体实现提供了一个带有特定签名的静态工厂方法。这将允许我使用Class.forName()
获取对具体类的引用,并确保我可以在我选择的约定中构造一个。
答案 4 :(得分:0)
另一种选择是在基类中将字段定义为public(最后,如果您愿意),然后在基类的构造函数中初始化该字段,具体取决于当前使用的子类。它有点阴暗,因为它引入了循环依赖。但是,至少它不是一个可以改变的依赖 - 即,子类将存在或不存在,但子类的方法或字段不能影响field
的值。
public abstract class Base {
public final int field;
public Base() {
if (this instanceof SubClassOne) {
field = 1;
} else if (this instanceof SubClassTwo) {
field = 2;
} else {
// assertion, thrown exception, set to -1, whatever you want to do
// to trigger an error
field = -1;
}
}
}