Class的实例是不可变的吗?

问题描述 投票:1回答:2

我想知道Class实例是否是不可变的。声明的方法名称并不表示实例状态在调用时会发生更改,但我发现javadoc没有明确的保证。

场景:我需要在Set中存储唯一的类名。理想情况下,我想用Class实例填充集合,以避免在需要通过反射访问classe时对Class.forName()进行不必要的调用。但是,最好使用不可变对象作为集合的键。因此,我想知道我是否可以立即使用Class实例。

java reflection set immutability
2个回答
4
投票

首先,泛型部分Class<?>在这里无所谓。当然,没有原始类型,所以Class<?>比Class更好,但对于你的问题,通配符并不重要。

所以从本质上讲,你要问的是Class对象是不可变的。并且出于所有实际目的,他们是。

当类加载器加载一个类时,类对象就会存在,除非整个类加载器被卸载,并且它加载了所有类加载器,否则它们会保持不变。

当这样的类对象仍在某个地图中使用时,这种情况不会发生。

另一方面:Class.forName()对于已经加载的类来说不应该太昂贵。当序列化等事情发挥作用时,人们建议使用String而不是Class对象(参见here)。

必须区分类对象的不可变身份和属于该类的实际“代码”。该代码可以在运行时更改(通过检测,考虑热插拔代码)。但是类名,它的每个代码和equals()相等都不应该受到影响。因为“身份”保持不变。

最后注意事项:正如下面的有趣评论所述,有一些方法可以在一定程度上改变Class对象。但所有这些活动肯定是“超出常态”。因此:理论上,您可能更喜欢Strings over Class对象,但实际上,在“普通”应用程序中,使用Class也应该可以正常工作。


0
投票

由于我不同意其他答案我决定写这个, 类不是不可变的,但它们是唯一的 - 一个类只能存在一个Class对象的实例。

但是它没有通过名称定义类,因为类可能来自不同的类加载器,并且不同的类加载器可能具有相同名称的类 - 但是这将是不同的类,如果要在处理的代码之间传递一些对象,则会得到ClassCastException 2个不同的类加载器,如果它们都存在于那两个对象类型中(作为单独的一个,不是继承的)。

类实例仍然可以在Set中安全使用,因为它们使用hashset / equals的默认实现,因此只有Class的相同实例才会被视为等于。

但是要决定是否应该使用StringClass,你需要知道你的应用程序应该如何工作,就像我说的那样,不同类加载器之间可以存在多个具有相同名称的类。

通过只存储类名,您不能确定Class.forName将返回预期的相同实例,它甚至可能从当前类加载器加载其他具有相同名称的类而不是使用预期的类。

© www.soinside.com 2019 - 2024. All rights reserved.