Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中返回有限数量的缓存实例?_Java_Enums_Singleton_Factory Pattern - Fatal编程技术网

如何在Java中返回有限数量的缓存实例?

如何在Java中返回有限数量的缓存实例?,java,enums,singleton,factory-pattern,Java,Enums,Singleton,Factory Pattern,我有一个“配置”类,它成为其他几个类的字段。它表示其他类允许或不允许操作的某种配置或“能力”。到目前为止,configuration类包含一组四个独立的Boolean,并且很可能保持这种状态,或者与另一个bolean一起增长。配置是不可变的:一旦创建了对象,配置将永远不会更改 public class Configuration { private final boolean abilityOne; private final boolean abilityTwo; pr

我有一个“配置”类,它成为其他几个类的字段。它表示其他类允许或不允许操作的某种配置或“能力”。到目前为止,configuration类包含一组四个独立的Boolean,并且很可能保持这种状态,或者与另一个bolean一起增长。配置是不可变的:一旦创建了对象,配置将永远不会更改

public class Configuration {
    private final boolean abilityOne;
    private final boolean abilityTwo;
    private final boolean abilityThree;
    private final boolean abilityFour;

    public Configuration (final boolean abilityOne, final boolean abilityTwo,
                          final boolean abilityThree, final boolean abilityFour) {
    this.configuration = ((1 * (abilityOne ? 1 : 0)) +
            (2 * (abilityTwo ? 1 : 0)) +
            (4 * (abilityThree ? 1 : 0)) +
            (8 * (abilityFour ? 1 : 0)));
 }

    public boolean isAbilityOne() {
        return((1 & this.configuration) > 0);
    }

    public boolean isAbilityTwo() {
        return((2 & this.configuration) > 0);
    }

    public boolean isAbilityThree() {
        return((4 & this.configuration) > 0);
    }

    public boolean isAbilityFour() {
        return((8 & this.configuration) > 0);
    }
}
由于C/有限的硬件背景,我的下一个实现(尝试减少内存占用)是使用
int
作为位图:1->first boolean,2->second,4->third,8->fourth。这样我存储了一个整数,我需要的布尔函数如下:


它工作得很好,内存效率也很高。但我的Java和我的同事们一辈子都不喜欢它


不同配置的数量是有限的(布尔值的组合),但使用它们的对象数量非常大。为了减少内存消耗,我想到了某种“多单例”、枚举或缓存实例。这就是我现在所在的地方。什么是最好的?

我建议如下,它很容易扩展,因为您只需向枚举添加另一个功能

enum Ability {
    Ability1, Ability2, Ability3, Ability4
}

public class Configuration {

   private static LoadingCache<Set<Ability>, Configuration> cache = CacheBuilder.newBuilder()
        .build(new CacheLoader<Set<Ability>, Configuration>() {
            @Override
            public Configuration load(Set<Ability> withAbilities) {
                return new Configuration(withAbilities);
            }

        });

    Set<Ability> abilities;

    private Configuration(Collection<Ability> withAbilities) {
        this.abilities = createAbilitySet(withAbilities);
    }

    public static Configuration create(Ability... withAbilities) {
        Set<Ability> searchedAbilities = createAbilitySet(Arrays.asList(withAbilities));
        try {
            return cache.get(searchedAbilities);
        } catch (ExecutionException e) {
            Throwables.propagateIfPossible(e);
            throw new IllegalStateException();
        }
    }

    private static Set<Ability> createAbilitySet(Collection<Ability> fromAbilities) {
        if (fromAbilities.size() == 0) {
            return Collections.emptySet();
        } else {
           return EnumSet.copyOf(fromAbilities);
        }
    }

    public boolean hasAbility(Ability ability) {
       return abilities.contains(ability);
    }
}
枚举能力{
能力1,能力2,能力3,能力4
}
公共类配置{
private static LoadingCache cache=CacheBuilder.newBuilder()
.build(新的缓存加载程序(){
@凌驾
公共配置负载(设置为能力){
返回新配置(带能力);
}
});
设定能力;
专用配置(收集功能){
this.abilities=createAbilitySet(withAbilities);
}
公共静态配置创建(能力…WithCapabilities){
设置searchedAbilities=createAbilitySet(Arrays.asList(withAbilities));
试一试{
返回cache.get(searchedAbilities);
}捕获(执行例外){
丢弃物。如果可能(e);
抛出新的非法状态异常();
}
}
私有静态集createAbilitySet(收集自能力){
if(fromAbabilities.size()==0){
返回集合;
}否则{
返回EnumSet.copyOf(fromCapabilities);
}
}
公共布尔hasAbility(能力){
返回能力。包含(能力);
}
}

我认为多音模式是最有效的方法:

public class Configuration {

    private static Map<Long, Configuration> configurations = new HashMap<>();

    private long key;
    private long value;

    public static Configuration getInstanse(long key, boolean... configs) {
        if (configurations.containsKey(key)) {
            return configurations.get(key).setConfigs(configs);
        }
        Configuration configuration = new Configuration(key, configs);
        configurations.put(key, configuration);
        return configuration;
    }

    // Max number of configs.length is 64
    private Configuration(long key, boolean... configs) {
        this.key = key;
        setConfigs(configs);
    }

    private Configuration setConfigs(boolean[] configs) {
        this.value = 0L;
        boolean config;
        for (int i = 0; i < configs.length; i++) {
            config = configs[i];
            this.value = this.value | (config ? (1L << i) : 0L);
        }
    }

    public long getKey() {
        return key;
    }

    public boolean getConfig(int place) {
        return (value & (1L << place)) == (1L << place);
    }
}
公共类配置{
私有静态映射配置=新HashMap();
私钥;
私人长期价值;
公共静态配置GetInstance(长键、布尔值…配置){
if(配置。容器(键)){
返回configurations.get(key).setConfigs(configs);
}
配置=新配置(键,配置);
配置。put(键、配置);
返回配置;
}
//最大配置数。长度为64
专用配置(长密钥、布尔值…配置){
this.key=key;
setConfigs(configs);
}
专用配置集配置(布尔[]配置){
该值为0升;
布尔配置;
对于(int i=0;ithis.value=this.value |(config?(1L如果配置实现对象较小且创建成本不高,则无需缓存它们。因为每个monster对象都必须保留对其每个配置的引用,并且在机器级别上,引用是指针,并且使用的内存至少与int相同

@gamulf提出的EnumSet方法可能可以在没有任何缓存的情况下使用,因为根据EnumSet javadoc:

枚举集在内部表示为位向量。这种表示非常紧凑和高效。此类的空间和时间性能应该足够好,可以作为传统的基于int的“位标志”的高质量、类型安全的替代品

我没有对它进行基准测试,但是缓存对于@gamulf的解决方案可能是无用的,因为一个配置对象只包含一个只包含一个int的EnumSet

如果您有一个很重的配置类(在内存方面或创建成本很高),并且只有少量可能的配置,那么您可以在类中使用一个静态HashSet成员,以及一个将返回缓存对象的静态工厂方法:

public class Configuration {
    static Set<Configuration > confs = new HashSet<>();
    ...

    public Configuration (Ability ... abs) {
        ...
    }

    public boolean hasAbility(Ability ab) {
        ...
    }

    static Configuration getConfiguration(Ability ... abs) {
        for (ConfImpl2 conf: confs) {
            if (conf.isSame(abs)) { return conf; }
        }
        ConfImpl2 conf = new ConfImpl2(abs);
        confs.add(conf);
        return conf;
    }
    private boolean isSame(Ability ... abs) {
        // ensures that this configuration has all the required abilities and only them
        ...
    }
}
公共类配置{
static Set confs=new HashSet();
...
公共配置(能力…abs){
...
}
公共布尔hasAbility(能力ab){
...
}
静态配置getConfiguration(能力…abs){
对于(ConfImpl2 conf:confs){
if(conf.isSame(abs)){return conf;}
}
ConfImpl2 conf=新ConfImpl2(abs);
会议增补(conf);
返回形态;
}
私有布尔值IsName(能力…abs){
//确保此配置具有所有必需的功能,并且仅具有这些功能
...
}
}

但正如我已经说过的,对于@gamulf所提出的那些轻量级的物体来说,这可能是无用的。我想分享我根据你的答案所做的调查,所以我发布了一个答案和这些结果。这样,我可能会更清楚为什么我选择一个答案而不是另一个

裸结果排名如下(用于600个“怪物”对象的内存,所需内存的10%:

  • 小选项:内部有四个布尔值的类:
    22.200.040
  • 初始选项:使用一个整数作为位映射初始化:
    22.200.040
  • “multiton”选项:一个工厂类,返回对普通选项类的引用:
    4.440.040
  • 枚举集(不带番石榴缓存)