Java 中抽象属性的解决方法
在 Scala 中,我会编写一个带有抽象属性 path
的抽象类:
abstract class Base {
val path: String
}
class Sub extends Base {
override val path = "/demo/"
}
Java 不知道抽象属性,我想知道解决此限制的最佳方法是什么。
我的想法:
a) 构造函数参数
abstract class Base {
protected String path;
protected Base(String path) {
this.path = path;
}
}
class Sub extends Base {
public Sub() {
super("/demo/");
}
}
b) 抽象方法
abstract class Base { // could be an interface too
abstract String getPath();
}
class Sub extends Base {
public String getPath() {
return "/demo/";
}
}
你更喜欢哪一个?还有其他想法吗?
我倾向于使用构造函数,因为不应在运行时计算路径值。
In Scala I would write an abstract class with an abstract attribute path
:
abstract class Base {
val path: String
}
class Sub extends Base {
override val path = "/demo/"
}
Java doesn't know abstract attributes and I wonder what would be the best way to work around this limitation.
My ideas:
a) constructor parameter
abstract class Base {
protected String path;
protected Base(String path) {
this.path = path;
}
}
class Sub extends Base {
public Sub() {
super("/demo/");
}
}
b) abstract method
abstract class Base { // could be an interface too
abstract String getPath();
}
class Sub extends Base {
public String getPath() {
return "/demo/";
}
}
Which one do you like better? Other ideas?
I tend to use the constructor since the path value should not be computed at runtime.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
Scala 内部所做的就是您所描述的方法 B。
以下面的示例类为例:
当您使用 scalac 编译该类时,它将生成一个抽象 Java 类,其中包含一个名为 attr 的抽象方法,该方法返回一个 String。发生这种情况的原因是,因为 val 是常量,因此它只能由 getter 模拟,而不能由 setter 模拟。所以如果你想从Java访问这个类,你可以简单地重写抽象的getter方法。
这相当于将生成的 Java 类(javap 的输出):
What Scala does internally is what you are describing as method B.
Take the following example class:
When you compile this with scalac, it will generate an abstract Java class with an abstract method named attr that returns a String. The reason this can happen is, because a val is constant and as such it can be emulated by only a getter and no setter. So if you want to access this class from Java, you can simply override the abstract getter method.
This is the equivalent of the Java class that will be produced (output of javap):
如果
path
永远不会改变,我会选择选项 a,否则我会选择选项 b。另一方面是
path
的值在构建时可能不可用。在这种情况下,选项a就被排除了。然而,与您的 Scala 代码相比,似乎path
在构建时可用。If the
path
never changes, I would go for option a, otherwise I would go for option b.Another aspect is that the value of
path
may not be available at the time of the construction. In that case option a is sort of ruled out. Comparing to your Scala code however, it seems likepath
is available at the time of the construction.由于值是固定的,因此等效为 B。
选项A接收构造函数中的路径,并且该值可以在运行时计算,这不是scala示例中的
Sub
类的内容。The equivalent is B since the values is fixed.
Option A receives the path in the constructor, and that value could be computed during runtime which is not what the
Sub
class in the scala example is goind.您可以尝试创建一个
protected
方法来设置变量的值。只能从同一包中的类调用。You could try creating a
protected
method to set the value of the variable. Callable only from classes in the same package.我会选择选项 b,因为如果出于某种原因路径依赖于其他属性,那么每次另一个属性更改时在超类中设置该属性并不是很好。
如果你必须实现 getter,那就没有问题了。
我想不出选项 a 更有用的任何具体情况。
I'd choose option b because if, for any reason, a path is dependent on other attributes then it's not really nice to set the attribute in the superclass every time another attribute changes.
If you have to implement the getter, then there's no problem.
I can't think of any specific case where option a would be more usable.
两者都可能很好 - 如果永远不会涉及任何计算,构造函数参数可能会更简单(在这种情况下,您可能希望将该字段设置为最终字段,这将具有确保它由可能是的任何其他构造函数设置的额外优势。稍后添加);而抽象方法给了你更多的自由来改变未来的事情。
您还可以将两者结合起来,并在构造函数中设置一个私有字段,并提供访问它的 getter 的具体(但不是最终)实现。
Either is probably fine - the constructor parameter is probable simpler if there will never be any computation involved (in which case you may want to make the field final, which will have the added advantage of making sure it's set by any other constructors that may be added later); whilst the abstract method gives you more freedom to change things in the future.
You could also combine the two, and have a private field set in the constructor and provide a concrete (but not final) implementation of the getter which accesses it.