static and final in java



我在这一页上读到了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声明为staticfinal?接下来,使用一个静态循环来初始化protoDeck。我知道静态变量在对象实例之间保持其值。但这是一个单例类(私有构造函数),因此无法实例化。

那么,这样做有什么好处呢?如果proteDeck不是staticfinal,会有什么影响?

从技术上讲,这不是一个单例类。(一个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永远不会被替换(尽管它可以在内部更改)。

最新更新