Java 为什么不抽象字段?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2211002/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why not abstract fields?
提问by Paul Reiners
Why can't Java classes have abstract fields like they can have abstract methods?
为什么 Java 类不能像抽象方法那样有抽象字段?
For example: I have two classes that extend the same abstract base class. These two classes each have a method that is identical except for a String constant, which happens to be an error message, within them. If fields could be abstract, I could make this constant abstract and pull the method up into the base class. Instead, I have to create an abstract method, called getErrMsg()
in this case, that returns the String, override this method in the two derived classes, and then I can pull up the method (which now calls the abstract method).
例如:我有两个扩展同一个抽象基类的类。这两个类每个都有一个相同的方法,除了其中的一个 String 常量(恰好是一条错误消息)。如果字段可以是抽象的,我可以使这个常量抽象并将该方法拉到基类中。相反,我必须创建一个抽象方法,getErrMsg()
在这种情况下调用,返回字符串,在两个派生类中覆盖此方法,然后我可以拉出该方法(现在调用抽象方法)。
Why couldn't I just make the field abstract to begin with? Could Java have been designed to allow this?
为什么我不能让这个领域一开始就抽象化?Java 是否可以设计为允许这样做?
采纳答案by rsp
You can do what you described by having a final field in your abstract class that is initialised in its constructor (untested code):
您可以通过在其构造函数(未经测试的代码)中初始化的抽象类中的 final 字段来执行您所描述的操作:
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";
}
}
If your child class "forgets" to initialise the final through the super constructor the compiler will give a warningan error, just like when an abstract method is not implemented.
如果您的子类“忘记”通过超级构造函数初始化 final,编译器将发出警告错误,就像未实现抽象方法一样。
回答by Laurence Gonsalves
Obviously it couldhave been designed to allow this, but under the covers it'd still have to do dynamic dispatch, and hence a method call. Java's design (at least in the early days) was, to some extent, an attempt to be minimalist. That is, the designers tried to avoid adding new features if they could be easily simulated by other features already in the language.
显然,它本来可以设计为允许这样做,但在幕后,它仍然必须进行动态分派,因此需要进行方法调用。Java 的设计(至少在早期)在某种程度上是一种极简主义的尝试。也就是说,如果语言中已有的其他功能可以轻松模拟新功能,则设计人员会尽量避免添加新功能。
回答by Felix Kling
I see no point in that. You can move the function to the abstract class and just override some protected field. I don't know if this works with constants but the effect is the same:
我认为这没有任何意义。您可以将函数移动到抽象类,只需覆盖一些受保护的字段。我不知道这是否适用于常量,但效果是一样的:
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";
}
}
So your point is that you want to enforce the implementation/overriding/whatever of errorMsg
in the subclasses? I thought you just wanted to have the method in the base class and didn't know how to deal with the field then.
所以你的观点是你想errorMsg
在子类中强制执行/覆盖/什么?我以为你只是想在基类中拥有方法,然后不知道如何处理该字段。
回答by Drew Wills
Reading your title, I thought you were referring to abstract instance members; and I couldn't see much use for them. But abstract static members is another matter entirely.
读你的标题,我以为你指的是抽象实例成员;我看不出它们有多大用处。但抽象静态成员完全是另一回事。
I have often wished that I could declare a method like the following in Java:
我经常希望我可以在 Java 中声明一个如下所示的方法:
public abstract class MyClass {
public static abstract MyClass createInstance();
// more stuff...
}
Basically, I would like to insist that concrete implementations of my parent class provide a static factory method with a specific signature. This would allow me to get a reference to a concrete class with Class.forName()
and be certain that I could construct one in a convention of my choosing.
基本上,我想坚持我的父类的具体实现提供具有特定签名的静态工厂方法。这将允许我获得对具体类的引用,Class.forName()
并确保我可以按照我选择的约定构造一个类。
回答by ragerdl
Another option is to define the field as a public (final, if you like) in the base class, and then initialize that field in the constructor of the base class, depending upon which subclass is currently being used. It's a bit shady, in that it introduces a circular dependency. But, at least it's not a dependency that can ever change -- i.e., the subclass will either exist or not exist, but the subclass's methods or fields can not influence the value of field
.
另一种选择是在基类中将该字段定义为公共(最终,如果您愿意),然后在基类的构造函数中初始化该字段,具体取决于当前使用的子类。这有点阴暗,因为它引入了循环依赖。但是,至少它不是一个可以改变的依赖——即,子类要么存在,要么不存在,但是子类的方法或字段不能影响 的值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;
}
}
}