有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将一个类中声明的所有字符串常量及其内部类放在一个键集中

可能隐藏的问题是,对于具有某种层次结构的键,应该使用哪种结构(因此,我尝试使用类和内部类,以便可以对特定子集进行测试)。我正在寻找一种结构,在这种结构中,我可以在适当的位置添加一个新的键,并自动将该键放入适当的键集中。下面是我的实际尝试: 现在,我使用键作为静态最终字符串和相应的键集。 我经常需要测试某个键是否包含在其他类中声明的一组键(公共静态最终字符串)中。 因此,我从一个Keys1类扩展了所有具有键的类,该类有一个方法keySet(),该方法给出了键集。很好

public class Keys1
{
    private TreeSet<String> m_keySet = new TreeSet<String>();    

    public Keys1()
    {
        initKeySet();
    }       

    private void initKeySet()
    {

        Field[] felder = this.getClass().getFields();
        for (Field f : felder)
        {
            if (Modifier.isFinal(f.getModifiers()))
            {               
                try
                {
                    if (f.get(f) instanceof String)
                    {
                        m_keySet.add(f.get(f).toString());
                    }
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }
    }


    public TreeSet<String> keySet()
    {
        return m_keySet;
    }       
}

现在,我试图在Keys2类中编写一个类似的功能,其中keySet还应该包含在Keys2类型的内部类中声明的键,但没有成功

public class Keys2 extends Keys1
{
    @Override
    protected void initKeySet()
    {
        super.initKeySet();

        Class<?>[] innerClasses = this.getClass().getDeclaredClasses();
        for (Class<?> innerClass : innerClasses )
        {
            if (innerClass.getClass().isInstance(Keys1.class))
            {
                Keys1 newKeys;
                try
                {
                    newKeys = (Keys1) innerClass.newInstance();  // Doesn't work
                    keySet().addAll(newKeys.keySet());
                }
                catch (InstantiationException e)
                {
                    e.printStackTrace();
                }
                catch (IllegalAccessException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

共 (1) 个答案

  1. # 1 楼答案

    既然您说过,您只在寻找public static final String字段,那么您正在做不必要的工作。您没有筛选字段以仅访问static字段,而且,您正在查询字段并检查结果的类型,而不是首先检查字段的类型

    此外,检索static字段不需要对象实例。如果代码是在Class上运行的,那么它可以用来处理发现的内部类,而无需实例化它们

    由于此过程不需要对象实例,因此也没有理由对每个实例重复该操作,也没有理由将结果存储在实例字段中。你只需要记住每个类的结果,谢天谢地,有一个名为^{}的类免费提供了这个结果

    把它放在一起,你就可以实现它

    public class Keys1 {
        static final ClassValue<TreeSet<String>> KEYS = new ClassValue<TreeSet<String>>() {
            @Override protected TreeSet<String> computeValue(Class<?> type) {
                final int desired=Modifier.PUBLIC|Modifier.STATIC|Modifier.FINAL;
                Field[] fields=type.getDeclaredFields();
                TreeSet<String> set = new TreeSet<>();
                for(Field f: fields) {
                    if((f.getModifiers()&desired)==desired && f.getType()==String.class) try {
                        set.add((String)f.get(null));
                    } catch(IllegalAccessException ex) {
                        throw new AssertionError(ex);
                    }
                }
                for(Class<?> inner: type.getDeclaredClasses()) {
                    set.addAll(get(inner));
                }
                type = type.getSuperclass();
                if(type != null && type != Object.class) set.addAll(get(type));
                return set;
            }
        };
        public TreeSet<String> keySet() {
            return KEYS.get(getClass());
        }
    }
    

    {}负责缓存。调用get时,它会检查指定类是否已经有计算值,否则,它会调用computeValue。这个解决方案中的computeValue方法利用它本身来处理超类字段,因此如果您为不同的子类调用它,它们将共享公共基类的结果,而不是重复工作

    子类在这里不需要做任何事情,继承的keySet()方法就足够了,因为它使用getClass(),返回实际的类

    如图ideone demo所示


    当您在Java 7之前的Java版本中运行时,可以使用下面的ersatz,当您迁移到新的Java版本时,应该立即用真实的东西替换它

    /**
     * TODO: replace with {@code java.lang.ClassValue<T>} when migrating to &gt;=7.
     */
    abstract class ClassValue<T> {
        private final ConcurrentHashMap<Class<?>,T> cache=new ConcurrentHashMap<Class<?>,T>();
        protected abstract T computeValue(Class<?> type);
        public final T get(Class<?> key) {
            T previous = cache.get(key);
            if(previous != null) return previous;
            T computed = computeValue(key);
            previous = cache.putIfAbsent(key, computed);
            return previous!=null? previous: computed;
        }
    }
    

    解决方案本身所需的唯一变化是替换菱形操作符使用
    new TreeSet<>()与显式类型的new TreeSet<String>()。然后,它应该在Java6中工作