我正在从this页面阅读Java中的枚举示例。
在第一个示例中,我唯一不理解的部分是在此部分代码中使用static
关键字:
private static final List<Card> protoDeck = new ArrayList<Card>();
// Initialize prototype deck
static {
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
protoDeck.add(new Card(rank, suit));
}
public static ArrayList<Card> newDeck() {
return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
}
为什么protoDeck声明static
和final
?然后,使用静态循环初始化protoDeck。我知道静态变量,它们在对象实例之间保留它们的值。但这是一个单例类(私有构造函数),因此无法实例化。
那么这样做的好处是什么?如果proteDeck不是static
和final
会产生什么影响?
答案 0 :(得分:2)
从技术上讲,这是不是单例类。 (单身人员有一个实例,这个实例 none !)
对于ArrayList<Card>
,它是工厂方法,方法newDeck
的工作方式与构造函数对“CardArrayList”类的工作方式相同。它不是Java构造函数,而是工厂方法,但除此之外它起到同样的作用:创建新的卡片组。
使用课程CardArrayList
和子类型ArrayList
显然是另类选择。试试这个练习:写一下类,这样就可以达到同样的目的。尝试使用常量(static final
)来保留初始对象集。您会注意到这两者之间几乎没有什么区别,除了这种方法清楚地表明没有附加功能,但结果是“除了包含完整套牌的ArrayList<Card>
之外”。子类化可能意味着有额外的功能,例如确保卡板不会被搞乱。
static final
变量包含用作新对象模板的原型。
答案 1 :(得分:1)
您的代码的静态{....}部分将在Java虚拟机加载类的位置执行。
在您的代码段中,它用于初始化protoDeck ArrayList。
这不遵循Singleton模式,因为您的代码中没有证据表明该类只被实例化了一次。
答案 2 :(得分:1)
在类初始化(static
括号中的代码)中,程序生成卡片的所有卡片并将其存储在protoDeck
中。
调用newDeck
时,将返回卡组的浅表副本。这意味着游戏中的所有牌对象都是同一个对象(只有一张“黑桃王牌”牌)。不过,它们在几个不同的套牌中进行管理。
恕我直言,对于这个例子来说这有点太复杂了,如果不是Cards
而不是{{1}}那么其他类(一个初始化在RAM中代价高昂/昂贵,或者其他代表它们的地方)会更有意义系统资源 - 数据库连接或类似 - )。
答案 3 :(得分:0)
如果它不是静态的,代码将无法编译,因为newDeck方法是静态的,而newDeck是静态的,因为你没有为不同的卡获得不同的套牌。
让它不是最终的不会做任何不同的事情。这是最终的,因为你不能分配不同的数组。但你仍然可以添加它,所以它不是一成不变的。所以这是一个常见的线索,但不是行为的改变。
答案 4 :(得分:0)
Java中的final
关键字支持各种编译时魔术。例如,当编译器知道永远不会重新分配变量时,它可以执行“memoization”优化。
单独这是final
的一个很好的理由 - 默认情况下使用局部变量,参数和类成员 - 除非你真的必须能够重新分配它们,当然。
答案 5 :(得分:0)
如果protoDeck
不是static
,则每个Card
会有一个static
,这不会是一件好事。
显然,您只能使用static
代码构建final
变量。
protoDeck
只是意味着永远不会替换{{1}}(尽管可以在内部进行更改)。