1

我正在从这个页面阅读 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
}

为什么要声明 protoDeckstaticfinal?之后,使用静态循环来初始化 protoDeck。我知道静态变量在对象实例之间保留它们的值。但这是一个单例类(私有构造函数),所以不能实例化。

那么像上面那样做有什么好处呢?如果 proteDeck 不是static并且会有什么影响final

4

6 回答 6

2

从技术上讲,这不是一个单例类。(单例有一个实例,这个没有!)

它是 的工厂方法ArrayList<Card>该方法newDeck的工作方式与类“CardArrayList”的构造函数相同。它不是 Java 构造函数,而是工厂方法,但除此之外,它的用途相同:创建新的卡片组。

使用类CardArrayList和子类型ArrayList显然是一种选择。尝试将此作为练习:编写诸如 class 之类的内容,以达到相同的目的。尝试使用常量 ( static final) 来保留初始对象集。您会注意到这两者之间几乎没有区别,只是这种方法清楚地表明没有附加功能,但结果是“除了ArrayList<Card>包含一个完整的套牌之外什么都没有”。子类化可能意味着有额外的功能,例如确保甲板不被弄乱。

static final变量包含用作新对象模板的原型。

于 2012-09-22T19:24:44.170 回答
1

您的代码的静态 { .... } 部分将在 Java 虚拟机加载您的类的位置执行。

在您的代码段中,它用于初始化 protoDeck ArrayList。

这不遵循单例模式,因为您的代码中没有证据表明该类仅被实例化一次。

于 2012-09-22T19:29:16.577 回答
1

在类初始化(static括号中的代码)中,程序生成所有牌组并将其存储在protoDeck.

newDeck被调用时,将返回该牌组的浅表副本。这意味着游戏中所有的牌对象都是同一个对象(只有一张“黑桃 A”牌)。不过,它们是在几个不同的牌组中管理的。

恕我直言,这个例子有点太复杂了,如果不是Cards其他类型的类(在 RAM 中初始化成本高/昂贵的类,或者代表系统资源的其他类 - 数据库连接或类似类 - )。

于 2012-09-22T19:32:28.023 回答
0

如果它不是静态的,则代码将无法编译,因为 newDeck 方法是静态的,而 newDeck 是静态的,因为您不会为不同的卡片获得不同的牌组。

让它不是最终的不会做任何不同的事情。这是最终的,因为您不能分配不同的数组。但是你仍然可以添加它,所以它不是一成不变的。所以这是一个常见的线索,但不是行为上的改变。

于 2012-09-22T19:24:33.607 回答
0

Java 中的final关键字启用了各种编译时魔法。例如,当编译器知道一个变量永远不会被重新分配时,它可以执行“记忆化”优化。

仅此一项就是默认 -ize 局部变量、参数和类成员的一个很好的理由final——当然,除非您真的必须能够重新分配它们。

于 2012-09-22T19:35:02.857 回答
0

如果protoDeck不是static每个人都有一个Card,那将不是一件好事。

Obviously, you can only construct a static variable with static code.

final just means the protoDeck will never be replaced (although it can be changed internally).

于 2012-09-22T19:37:38.520 回答