我在这一页上读到了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
,会有什么影响?
从技术上讲,这不是一个单例类。(一个singleton有一个实例,而这个实例没有!)
它是ArrayList<Card>
的工厂方法,方法newDeck
的工作方式与类"CardArrayList"的构造函数相同。它不是一个Java构造函数,而是一个工厂方法,但除此之外,它还有同样的用途:创建新的卡片组。
使用类CardArrayList
和子类型ArrayList
显然是一种替代方案。试着把它作为一个练习:写一个类,这样它就可以达到同样的目的。尝试使用常量(static final
)来保持对象的初始集合。您会注意到,这两者之间几乎没有什么区别,只是这种方法明确表示没有添加功能,但结果是"只有一个包含完整甲板的ArrayList<Card>
"。子类化可能意味着有额外的功能,比如确保甲板不会被弄乱。
static final
变量包含用作新对象模板的原型。
代码的静态{….}部分将在Java虚拟机加载类的地方执行。
在您的代码段中,它用于初始化protoDeck ArrayList。
这不是遵循Singleton模式,因为在您的代码中没有证据表明该类只实例化了一次。
在类初始化(static
括号中的代码)中,程序生成卡片组的所有卡片,并将其存储在protoDeck
中。
当调用newDeck
时,会返回一个浅层的甲板副本。这意味着游戏中所有的牌对象都是同一个对象(只有一张"黑桃王牌"牌)。不过,它们是在几个不同的甲板上管理的。
IMHO,对于这个例子来说,它有点太复杂了,如果不是Cards
,而不是其他类型的类(在RAM中初始化会很昂贵,或者在其他类中它们代表系统资源-数据库连接或类似-),它将更有意义。
如果它不是静态的,代码将不会编译,因为newDeck方法是静态的,而newDeck是静态的因为你不会为不同的卡获得不同的牌组。
不进入决赛不会有什么不同。最后一点是,您不能分配不同的数组。但是你仍然可以添加到它中,所以它不是一成不变的。因此,这是一个常见的线索,但不是行为的改变。
Java中的final
关键字可以实现各种编译时魔术。例如,当编译器知道永远不会重新分配变量时,它可以执行"内存化"优化。
这本身就是默认情况下final
大小局部变量、参数和类成员的一个很好的理由——当然,除非您真的必须能够重新分配它们。
如果protoDeck
不是static
,那么每个Card
都会有一个,这不是一件好事。
显然,您只能用static
代码构造一个static
变量。
final
只是意味着protoDeck
永远不会被替换(尽管它可以在内部更改)。