Java中的常量数组
我有一个Java中的常量数组,java,arrays,Java,Arrays,我有一个Move类,它是不可变的(基本上只有两个整数) I have类使用常量移动: public class Moves { public static final Move NW = Move.make(-1, -1); public static final Move N = Move.make(0, -1); public static final Move NE = Move.make(1, -1); public static final Move
Move
类,它是不可变的(基本上只有两个整数)
I have类使用常量移动
:
public class Moves {
public static final Move NW = Move.make(-1, -1);
public static final Move N = Move.make(0, -1);
public static final Move NE = Move.make(1, -1);
public static final Move E = Move.make(1, 0);
public static final Move SE = Move.make(1, 1);
public static final Move S = Move.make(0, 1);
public static final Move SW = Move.make(-1, 1);
public static final Move W = Move.make(-1, 0);
public final static Move[] ALL = {
NW, N, NE, E, SE, S, SW, W
};
public final static Move[] CARDINAL = {
N, E, S, W
};
}
我需要用于以下方法的数组:
public void walkToRandomSide(Move[] possibleMoves)
它工作得很好,但是很明显,ALL
和CARDINAL
的元素可以由任何人随时更改。当然,我知道这些元素不可能是最终的
这很糟糕——我希望它成为库的一部分,并且尽可能稳定和可预测
我该如何解决这个问题?
创建一个每次创建一个新数组的方法?数组始终是可修改的(注释中所述的零大小数组除外),您应该在此处使用
集合。不可修改列表。例如:
public final static List<Move> ALL =
Collections.unmodifiableList(Arrays.asList(NW, N, NE, E, SE, S, SW, W));
public最终静态列表所有=
集合.不可修改的列表(数组.asList(NW,N,NE,E,SE,S,SW,W));
数组始终是可修改的(注释中所述的零大小数组除外),您应该在此处使用集合。不可修改列表。例如:
public final static List<Move> ALL =
Collections.unmodifiableList(Arrays.asList(NW, N, NE, E, SE, S, SW, W));
public最终静态列表所有=
集合.不可修改的列表(数组.asList(NW,N,NE,E,SE,S,SW,W));
Java。在大多数其他语言中,它们的功能远远超过枚举,它们是final
类,具有一组特定的final
成员,这些成员是该类的唯一实例。如果您使用的是Java1.4或更高版本,则它们不可用,但这正是您所需要的。Java。在大多数其他语言中,它们的功能远远超过枚举,它们是final
类,具有一组特定的final
成员,这些成员是该类的唯一实例。如果您使用的是Java 1.4或更高版本,则它们不可用,但这正是您想要的。不,请避免使用数组。数组总是可变的,即使您每次创建一个新数组,这意味着您的调用者在传递集合时必须执行防御复制
首先,我要按照Steve的建议,将您的Move
类更改为enum。然后任何人都可以使用EnumSet.allOf
其次,对于CARDINAL
,我要么使用Collections.unmodifiableList
来包装您在内部创建的列表(并且知道您永远不会修改自己),要么使用一个明确谈论不可变性的类型,例如from(或者可能是ImmutableSet
,这取决于排序是否重要)
使用单独类型的好处是,您可以向调用者明确它是不可变的,而不仅仅是记录返回的列表恰好是不可变的。虽然通常使用接口作为返回类型是一个好主意,但在这里值得在类型系统中传达一个非常具体的保证-一个gu调用方也可以在其代码中使用的数组。不,只需避免使用数组。数组始终是可变的,即使您每次创建一个新数组,这意味着您的调用方在传递集合时也必须执行防御副本
首先,我会按照Steve的建议将您的Move
类更改为enum。然后任何人都可以使用EnumSet.allOf
其次,对于CARDINAL
,我要么使用Collections.unmodifiableList
来包装您在内部创建的列表(并且知道您永远不会修改自己),要么使用一个明确谈论不可变性的类型,例如from(或者可能是ImmutableSet
,这取决于排序是否重要)
使用单独类型的好处是,您可以向调用者明确它是不可变的,而不仅仅是记录返回的列表恰好是不可变的。虽然通常使用接口作为返回类型是一个好主意,但在这里值得在类型系统中传达一个非常具体的保证-一个gu调用方也可以在其代码中使用的数组。在get()方法中创建数组的防御副本,以便任何人都不能更改您的数组:
public Move[] getAll{
Move[] tmpArray = new Move[ALL.length];
for (int i = 0; i < All.length; i++) {
tmpArray[i] = All[i];
}
return tmpArray;
}
public Move[]getAll{
Move[]tmpArray=新移动[ALL.length];
for(int i=0;i
或者更好
public Move[] getAll{
Move[] tmpArray = new Move[ALL.length];
for (int i = 0; i < All.length; i++) {
tmpArray[i] = new Move(All[i]); // make sure to create a deep copy using copy constructor
}
return tmpArray;
}
public Move[]getAll{
Move[]tmpArray=新移动[ALL.length];
for(int i=0;i
在get()方法中创建阵列的防御副本,以便任何人都无法更改您的阵列:
public Move[] getAll{
Move[] tmpArray = new Move[ALL.length];
for (int i = 0; i < All.length; i++) {
tmpArray[i] = All[i];
}
return tmpArray;
}
public Move[]getAll{
Move[]tmpArray=新移动[ALL.length];
for(int i=0;i
或者更好
public Move[] getAll{
Move[] tmpArray = new Move[ALL.length];
for (int i = 0; i < All.length; i++) {
tmpArray[i] = new Move(All[i]); // make sure to create a deep copy using copy constructor
}
return tmpArray;
}
public Move[]getAll{
Move[]tmpArray=新移动[ALL.length];
for(int i=0;i
为什么不将常量定义为enum?使用私有构造函数创建一个enum!我想在循环中对它进行迭代,并且我需要基数和全部(+对角线,我在这里没有提到).Enum不能这样做。请参见JonSkeet关于EnumSet
的回答。为什么不将常量定义为Enum?使用私有构造函数创建一个Enum!我想在循环中对其进行迭代,并且我需要基数和全部(+对角线,我在这里没有提到).Enum不能这样做。请参阅JonSkeet关于EnumSet
的回答。好吧,我不能使用Enum-可能有人还想添加Move.make(2,1)等移动对于horse,它可以扩展到移动之外。但是不可变列表看起来可能会起作用。好吧,使用集合。不可修改列表
,因为我不想再向我的项目中添加另一个jar。嗯,我不能使用enum-可能有人还想添加移动,例如Move.make(2,1)for hors