有一段看起来像这样的代码。问题是在启动过程中会进行2次初始化。 (1)某些方法对ForumRepository
进行反射并纯粹执行newInstance()来调用#setCacheEngine
。 (2)随后的另一个方法调用#start()
。我注意到#cache
成员变量的hashCode在某些奇怪的情况下有时会有所不同。由于只有1段代码调用#setCacheEngine
,因此hashCode在运行时如何更改(我假设不同的实例将具有不同的hashCode)。这里某处有错误吗?
public class ForumRepository implements Cacheable
{
private static CacheEngine cache;
private static ForumRepository instance;
public void setCacheEngine(CacheEngine engine) { cache = engine; }
public synchronized static void start()
{
instance = new ForumRepository();
}
public synchronized static void addForum( ... )
{
cache.add( .. );
System.out.println( cache.hashCode() );
// snipped
}
public synchronized static void getForum( ... )
{
... cache.get( .. );
System.out.println( cache.hashCode() );
// snipped
}
}
整个系统通过servlet的
init
方法进行连接和初始化。init()方法在概念上看起来像这样:
// create an instance of the DefaultCacheEngine
cache = (CacheEngine)Class.forName( "com..DefaultCacheEngine" ).newInstance();
cache.init();
// init the ForumRepository's static member
Object o = Class.forName( "com.jforum....ForumRepository" ).newInstance();
if( o instanceof Cacheable )
((Cacheable)o).setCacheEngine(cache);
// Now start the ForumRepository
ForumRepository.start();
更新我没有写这段代码。它取自jforum
更新2找到解决方案。我在下面添加了单独的注释来描述问题的原因。谢谢大家。
最佳答案
您将不得不为此提供更多信息,但是CacheEngine
可能是可变的数据类型,更糟糕的是,它甚至可能被其他人共享。根据CacheEngine
定义其hashCode()
的方式,很可能导致aForumRepository
从其cache
看到各种不同的哈希码。
如果相同的对象是可变的,则最好在一段时间内更改其hashCode()
,只要它以一致的方式完成(这是另一个主题)。
也可以看看Object.hashCode()
-确保您了解合同的含义
在cache
被static
更多信息已经浮出水面,并且我们现在知道所讨论的对象虽然可变,却没有@Override hashCode()
。但是,在设计中似乎存在一个严重的问题,就是将cache
设置为static
类的ForumRepository
字段,并使用非static
“设置者” setCacheEngine
(看起来是由Cacheable
指定) )。
这意味着无论创建多少个cache
实例,都只有ForumRepository
的化身!在某种程度上,所有ForumRepository
实例都“共享”相同的cache
!
JLS 8.3.1.1 static
Fields
如果将一个字段声明为static
,则无论该类最终会创建多少个实例(可能为零),都只存在该字段的一个具体化身。初始化类时,会包含一个static
字段(有时称为类变量)。
我认为现在退后一步并提出以下问题很重要:cache
是否需要为static
?这是故意的吗?ForumRepository
实例是否应具有自己的cache
?
...还是应该全部“共享”相同的cache
?
将创建多少个ForumRepository
实例?
撇开设计模式的优缺点,ForumRepository
应该是单例吗?setCacheEngine
对象可以调用多少次?
如果多次调用ForumRepository
,它会从防御机制中受益吗?
最佳建议取决于上述问题的答案。第三个要点是可以立即执行的操作,可以显示IllegalStateException
是否被多次调用。即使对于每个setCacheEngine
实例仅对其调用一次,由于只有一个ForumRepository
,在当前事务状态下,它实际上仍然是多个“集合”。
具有非cache
设置符的static
字段是一项设计决策,需要彻底重新检查。