
[英]How to declare a private static final int from a method (java beginner)
[英]Proper way to declare and set a private final member variable from the constructor in Java?
有多种方法可以从构造函数中设置成员变量。 我实际上正在讨论如何正确设置最终成员变量,特别是一个由辅助类加载条目的映射。
public class Base {
private final Map<String, Command> availableCommands;
public Base() {
availableCommands = Helper.loadCommands();
}
}
在上面的例子中,helper类看起来像这样:
public class Helper {
public static Map<String, Command> loadCommands() {
Map<String, Command> commands = new HashMap<String, Command>();
commands.put("A", new CommandA());
commands.put("B", new CommandB());
commands.put("C", new CommandC());
return commands;
}
}
我的想法是,使用方法在构造函数中设置这样的变量是更好的做法。 所以Base类看起来像这样:
public class Base {
private final Map<String, Command> availableCommands;
public Base() {
this.setCommands();
}
private void setCommands() {
this.availableCommands = Helper.loadCommands();
}
}
但是现在我无法维护最终修饰符并得到编译器错误(无法设置最终变量)
另一种方法是:
public class Base {
private final Map<String, Command> availableCommands = new HashMap<String, Command>();
public Base() {
this.setCommands();
}
private void setCommands() {
Helper.loadCommands(availableCommands);
}
}
但在这种情况下,Helper类中的方法将更改为:
public static void loadCommands(Map<String, Command> commands) {
commands.put("A", new CommandA());
commands.put("B", new CommandB());
commands.put("C", new CommandC());
}
所以区别在于我在哪里用new HashMap<String, Command>();
创建一个新的地图new HashMap<String, Command>();
? 我的主要问题是,是否有推荐的方法来实现这一点,因为部分功能来自这个Helper的静态方法,作为一种用条目加载实际地图的方法?
我在Base类或Helper类中创建新地图吗? 在这两种情况下,Helper都会执行实际加载,Base对包含具体命令的地图的引用将是私有和最终的。
除了我正在考虑的选项之外,还有其他更优雅的方法吗?
根据你的第一个代码片段,帮助类创建地图对我来说似乎是完全合理的。 您在构造函数中设置变量 - 我看不到问题。
正如打哈欠所说,让地图不可变在这里会很好看,但除此之外,我只是使用第一段代码。
(我认为在现实生活中,这确实需要是一个实例变量,而不是静态变量,顺便说一下?)
如果您希望此类地图不可变,请查看Google Collection API 。 引用链接的文档:
static final ImmutableMap<String, Integer> WORD_TO_INT =
new ImmutableMap.Builder<String, Integer>()
.put("one", 1)
.put("two", 2)
.put("three", 3)
.build();
您是否考虑使用类似于Effective Java 2nd ed中的Builder模式。 ?
您可以在一个地方捕获所有地图构造逻辑(因此您不需要维护2个单独的类)。 Base将如下所示:
public class Base {
private final Map<String, Command> commands;
private Base(Builder b) {
commands = b.commands;
}
public static class Builder() {
private final Map<String, Command> commands;
public Builder() {
commands = new HashMap<String, Command>();
}
public Builder addCommand(String name, Command c) {
commands.put(name, c);
return this;
}
public Base build() {
return new Base(this);
}
}
}
Base的客户端现在可以像这样工作:
Base b = new Base.Builder().addCommand("c1", c1).addCommand("c2", c2).build();
Upshot是客户端类不需要知道他们需要构建一个Map,你实际上可以用1行构建它。 缺点是Base无法扩展,因为构造函数现在是私有的(也许你想要那个,也许你不需要)。
编辑:在build()中有一个goof我在那里传递命令而不是像我最初想要的 EDIT2:Mistakenly调用add而不是放入Base.Builder.addCommand
如果你想让它不可变,你不需要使用第三方API,你可以使用: java.util.Collections.unmodifiableMap(Map m)
最常见的方法是:
public class Base { private final Map availableCommands; public Base(){ availableCommands=new HashMap(); // or any other kind of map that you wish to load availableCommands = Helper.loadCommands(availableCommands); } }
你为什么不这样做呢
private final Map<String, Command> availableCommands = Helper.loadCommands();
?
我个人会将Helper类重命名为CommandHolder:
public class CommandHolder {
private static Map<String, Command> availableCommands;
private static CommandHolder instance;
private CommandHolder{}
public static synchronized Map<String, Command> getCommandMap() {
if (instance == null) {
instance = new CommandHolder();
instance.load();
}
return availableCommands
}
private void load() {
...
}
}
同步以确保加载仅发生一次。 没有getCommand,因为那个必须同步,每次查找都会更昂贵。 我假设地图是只读的,否则你无论如何都需要在多线程环境中使用synchronizedMap。
你也可以使用双支撑初始化,虽然你认为它是否更干净可能是一个品味的问题,但至少有一个好处,所有的初始化代码在一个地方:
public class Base {
public final Map< String, Command > availableCommands;
public Base() {
availableCommands = Collections.unmodifiableMap( new HashMap() {
{
put( "A", new CommandA() );
put( "B", new CommandB() );
}
} );
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.